diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..d2562341384530b51b5338ea53627fc11e100ba6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,13 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +pages/anagrafica.xlsx filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSans-Bold.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSans-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSans-ExtraLight.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSans-Oblique.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSans.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSansCondensed-Bold.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSansCondensed-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSansCondensed-Oblique.ttf filter=lfs diff=lfs merge=lfs -text +pages/DejaVuSansCondensed.ttf filter=lfs diff=lfs merge=lfs -text diff --git a/pages/.DS_Store b/pages/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..97781e623d0516a0b3952eb4a97b0c0d027bc20d Binary files /dev/null and b/pages/.DS_Store differ diff --git a/pages/.ipynb_checkpoints/CalcoloSomme-checkpoint.ipynb b/pages/.ipynb_checkpoints/CalcoloSomme-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..329686d1a03dbc7a7053d554dfd017994ed701b6 --- /dev/null +++ b/pages/.ipynb_checkpoints/CalcoloSomme-checkpoint.ipynb @@ -0,0 +1,6746 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "import copy\n", + "import openpyxl\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "#fn = \"JahresBericht_Ahrntal_2021.xlsx\"\n", + "fn = \"errori dopo modifica 2021 - Copy.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "afbfb93b", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "df = pd.read_excel(fn, sheet_name = 'ita',engine = 'openpyxl')#, skiprows = 8)\n", + "#df = pd.read_excel(fn,engine = 'openpyxl')#, skiprows = 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " #\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\",\n", + " #\"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2021\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6f06a836", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,\"Cognome e nome bambino\", df[\"Cognome\"] + ' ' + df[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b44721c6", + "metadata": {}, + "outputs": [], + "source": [ + "df.drop([\"Cognome\",\"Nome\"], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3bac24f2", + "metadata": {}, + "outputs": [], + "source": [ + "# df" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Casa Bimbo '" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "7e2e0f52", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = df.iloc[4]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "62c2a66b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Bolzano\n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale NaN\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 NaN\n", + "Ore totali rendicontate per il 2021 NaN\n", + "Name: 4, dtype: object" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "05d1e376", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = gemeinde[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "e4eca77c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Bolzano'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + "cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + "df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + "df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]\n", + "ddff = pd.DataFrame()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "eee9a6ec", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "ed99ae10", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "600803c2", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
81.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
6659.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "66 59.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 00:00:00 \n", + "66 2022-08-31 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132 \n", + "66 132 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "66 968.25 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "condizione1 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] >= pd.to_datetime(\"19.10.2020\", format=\"%d.%m.%Y\")\n", + "condizione2 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] < pd.to_datetime(\"22.10.2020\", format=\"%d.%m.%Y\")\n", + "df[condizione1 & condizione2]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "90008ae8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020',\n", + " 'Ore totali rendicontate per il 2021'],\n", + " dtype='object')" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2021" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "29ed03dd", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26365935.2521.25956.502021-01-012021-12-31
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01182605.500.00605.502021-01-012021-07-01
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0811084.000.0084.002021-02-192021-06-08
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03184690.0030.75720.752021-01-012021-07-03
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02365965.5022.50988.002021-01-012021-12-31
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17110462.500.00462.502021-09-132021-12-31
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-313651314.500.001314.502021-01-012021-12-31
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01117274.5039.00313.502021-09-062021-12-31
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06163592.0022.00614.002021-02-252021-08-06
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-023651269.7531.501301.252021-01-012021-12-31
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30151372.0020.00392.002021-03-022021-07-30
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171981010.5022.001032.502021-01-012021-07-17
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25176652.0030.00682.002021-01-012021-06-25
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29311940.500.00940.502021-02-242021-12-31
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-153651338.75110.001448.752021-01-012021-12-31
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28148575.500.00575.502021-01-012021-05-28
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31243812.2576.00888.252021-01-012021-08-31
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02183428.0020.00448.002021-01-012021-07-02
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02103474.5078.00552.502021-09-202021-12-31
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24236979.00110.001089.002021-01-012021-08-24
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-3189263.5058.50322.002021-10-042021-12-31
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31243806.500.00806.502021-01-012021-08-31
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-313651016.0060.001076.002021-01-012021-12-31
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02331616.000.00616.002021-02-042021-12-31
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-172695.000.0095.002021-12-062021-12-31
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31209488.0020.00508.002021-01-042021-07-31
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-3040140.000.00140.002021-11-222021-12-31
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31212587.7523.50611.252021-01-012021-07-31
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04216573.0020.00593.002021-01-012021-08-04
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-283651211.750.001211.752021-01-012021-12-31
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30211476.0020.00496.002021-01-012021-07-30
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27239469.5023.50493.002021-01-012021-08-27
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02306200.250.00200.252021-03-012021-12-31
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31243973.0095.001068.002021-01-012021-08-31
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01124493.5078.00571.502021-08-302021-12-31
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24236562.5022.50585.002021-01-012021-08-24
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16117427.250.00427.252021-09-062021-12-31
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06209950.7532.00982.752021-02-102021-09-06
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-313651405.0035.001440.002021-01-012021-12-31
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08281632.500.00632.502021-01-012021-10-08
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-0175248.250.00248.252021-10-182021-12-31
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-3082213.000.00213.002021-10-112021-12-31
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31124543.750.00543.752021-08-302021-12-31
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31221706.000.00706.002021-05-252021-12-31
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31212496.0020.00516.002021-01-012021-07-31
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-1754108.500.00108.502021-11-082021-12-31
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-043651353.2532.501385.752021-01-012021-12-31
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-313651643.50132.001775.502021-01-012021-12-31
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03246695.0063.00758.002021-01-012021-09-03
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10253879.5021.25900.752021-01-012021-09-10
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-0275276.000.00276.002021-10-182021-12-31
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-313651328.5025.001353.502021-01-012021-12-31
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30187543.000.00543.002021-06-282021-12-31
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01103401.500.00401.502021-09-202021-12-31
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-313651734.000.001734.002021-01-012021-12-31
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02124629.500.00629.502021-08-302021-12-31
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-263651152.5066.001218.502021-01-012021-12-31
66BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "66 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "66 2022-08-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 365 \n", + "10 182 \n", + "11 110 \n", + "12 184 \n", + "13 365 \n", + "14 110 \n", + "15 365 \n", + "16 117 \n", + "17 163 \n", + "18 365 \n", + "19 151 \n", + "20 198 \n", + "21 176 \n", + "22 311 \n", + "23 365 \n", + "24 148 \n", + "25 243 \n", + "26 183 \n", + "27 103 \n", + "28 236 \n", + "29 89 \n", + "30 243 \n", + "31 365 \n", + "32 331 \n", + "33 26 \n", + "34 209 \n", + "35 40 \n", + "36 212 \n", + "37 216 \n", + "38 365 \n", + "39 211 \n", + "40 239 \n", + "41 306 \n", + "42 243 \n", + "43 124 \n", + "44 236 \n", + "45 117 \n", + "46 209 \n", + "47 365 \n", + "48 281 \n", + "49 75 \n", + "50 82 \n", + "51 124 \n", + "52 221 \n", + "53 212 \n", + "54 54 \n", + "55 365 \n", + "56 365 \n", + "57 246 \n", + "58 253 \n", + "59 75 \n", + "60 365 \n", + "61 187 \n", + "62 103 \n", + "63 365 \n", + "64 124 \n", + "65 365 \n", + "66 365 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 968.25 2021-01-01 2021-12-31 \n", + "9 956.50 2021-01-01 2021-12-31 \n", + "10 605.50 2021-01-01 2021-07-01 \n", + "11 84.00 2021-02-19 2021-06-08 \n", + "12 720.75 2021-01-01 2021-07-03 \n", + "13 988.00 2021-01-01 2021-12-31 \n", + "14 462.50 2021-09-13 2021-12-31 \n", + "15 1314.50 2021-01-01 2021-12-31 \n", + "16 313.50 2021-09-06 2021-12-31 \n", + "17 614.00 2021-02-25 2021-08-06 \n", + "18 1301.25 2021-01-01 2021-12-31 \n", + "19 392.00 2021-03-02 2021-07-30 \n", + "20 1032.50 2021-01-01 2021-07-17 \n", + "21 682.00 2021-01-01 2021-06-25 \n", + "22 940.50 2021-02-24 2021-12-31 \n", + "23 1448.75 2021-01-01 2021-12-31 \n", + "24 575.50 2021-01-01 2021-05-28 \n", + "25 888.25 2021-01-01 2021-08-31 \n", + "26 448.00 2021-01-01 2021-07-02 \n", + "27 552.50 2021-09-20 2021-12-31 \n", + "28 1089.00 2021-01-01 2021-08-24 \n", + "29 322.00 2021-10-04 2021-12-31 \n", + "30 806.50 2021-01-01 2021-08-31 \n", + "31 1076.00 2021-01-01 2021-12-31 \n", + "32 616.00 2021-02-04 2021-12-31 \n", + "33 95.00 2021-12-06 2021-12-31 \n", + "34 508.00 2021-01-04 2021-07-31 \n", + "35 140.00 2021-11-22 2021-12-31 \n", + "36 611.25 2021-01-01 2021-07-31 \n", + "37 593.00 2021-01-01 2021-08-04 \n", + "38 1211.75 2021-01-01 2021-12-31 \n", + "39 496.00 2021-01-01 2021-07-30 \n", + "40 493.00 2021-01-01 2021-08-27 \n", + "41 200.25 2021-03-01 2021-12-31 \n", + "42 1068.00 2021-01-01 2021-08-31 \n", + "43 571.50 2021-08-30 2021-12-31 \n", + "44 585.00 2021-01-01 2021-08-24 \n", + "45 427.25 2021-09-06 2021-12-31 \n", + "46 982.75 2021-02-10 2021-09-06 \n", + "47 1440.00 2021-01-01 2021-12-31 \n", + "48 632.50 2021-01-01 2021-10-08 \n", + "49 248.25 2021-10-18 2021-12-31 \n", + "50 213.00 2021-10-11 2021-12-31 \n", + "51 543.75 2021-08-30 2021-12-31 \n", + "52 706.00 2021-05-25 2021-12-31 \n", + "53 516.00 2021-01-01 2021-07-31 \n", + "54 108.50 2021-11-08 2021-12-31 \n", + "55 1385.75 2021-01-01 2021-12-31 \n", + "56 1775.50 2021-01-01 2021-12-31 \n", + "57 758.00 2021-01-01 2021-09-03 \n", + "58 900.75 2021-01-01 2021-09-10 \n", + "59 276.00 2021-10-18 2021-12-31 \n", + "60 1353.50 2021-01-01 2021-12-31 \n", + "61 543.00 2021-06-28 2021-12-31 \n", + "62 401.50 2021-09-20 2021-12-31 \n", + "63 1734.00 2021-01-01 2021-12-31 \n", + "64 629.50 2021-08-30 2021-12-31 \n", + "65 1218.50 2021-01-01 2021-12-31 \n", + "66 968.25 2021-01-01 2021-12-31 " + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "id": "fcd45d79", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
8BAH MAMADOU ADAMA132.00
9TUCCIO GABRIEL21.25
10GAMBINO AMBRA0.00
11BISULTANOV MANSUR0.00
12DELVAI MATTEO30.75
13TOSI SOFIA22.50
14BRAHAJ SJORDI0.00
15BUCCELLA LORENZO0.00
16FIALCOVSCHI ALEXANDRU39.00
17CHIHI LISA22.00
18LANARI ARIANNA31.50
19PATRICELLI GIULIA20.00
20SMITH LIAM22.00
21CORNESCU DANIELE30.00
22SCARATTI FRANCESCA0.00
23BARDINI MARCO110.00
24DALL'ARMELLINA PIETRO0.00
25DE LUCIA MARTINA76.00
26DE PALMA ALESSANDRO20.00
27MOHAMMAD SALEEH BERITAN78.00
28PEREZZANI NOELLE110.00
29DI FEBBRAIO GIUSEPPE58.50
30DI PIERRO ALICE0.00
31DONOLA MATILDE60.00
32KHOUIA HIBA0.00
33KANOUNE MARYEM ELBATOUL0.00
34EL HAMDAOUI NIZAR20.00
35AYALA GALLEGOS JAYDEN0.00
36GASHI AMRA23.50
37SICOLO FRANCESCO20.00
38DI MARCO ANITA0.00
39HYSENAJ ESLI20.00
40BILAL SHAMIR23.50
41LLESHI DANIEL0.00
42LORENZINI MARINA95.00
43LOTIERZO NICOLO'78.00
44MIRA TEO22.50
45VENTURINI AURORA0.00
46MION GINEVRA32.00
47NEZA REAN35.00
48PEDINI LILIANA0.00
49PEREZ PONCE ELLIE0.00
50CIRILLO JACOPO0.00
51BAR NICHOLAS0.00
52CUEL MATAN0.00
53POPESCU MATEI20.00
54PASCARELLA DOMENICO0.00
55CAMPARETTO ROCCA EDOARDO32.50
56FIORE LEONARDO132.00
57DE COL BEATRICE63.00
58SOTA PAOLA21.25
59TATARI SAUL0.00
60TRINCO ANITA25.00
61VALLAZZA ISABEL0.00
62MANGIALAIO LEON0.00
63WEGLEITER ENEAS0.00
64SAID ZAYD0.00
65RINDONE FILIPPO TOMMASO66.00
66BAH MAMADOU ADAMA132.00
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino \\\n", + "8 BAH MAMADOU ADAMA \n", + "9 TUCCIO GABRIEL \n", + "10 GAMBINO AMBRA \n", + "11 BISULTANOV MANSUR \n", + "12 DELVAI MATTEO \n", + "13 TOSI SOFIA \n", + "14 BRAHAJ SJORDI \n", + "15 BUCCELLA LORENZO \n", + "16 FIALCOVSCHI ALEXANDRU \n", + "17 CHIHI LISA \n", + "18 LANARI ARIANNA \n", + "19 PATRICELLI GIULIA \n", + "20 SMITH LIAM \n", + "21 CORNESCU DANIELE \n", + "22 SCARATTI FRANCESCA \n", + "23 BARDINI MARCO \n", + "24 DALL'ARMELLINA PIETRO \n", + "25 DE LUCIA MARTINA \n", + "26 DE PALMA ALESSANDRO \n", + "27 MOHAMMAD SALEEH BERITAN \n", + "28 PEREZZANI NOELLE \n", + "29 DI FEBBRAIO GIUSEPPE \n", + "30 DI PIERRO ALICE \n", + "31 DONOLA MATILDE \n", + "32 KHOUIA HIBA \n", + "33 KANOUNE MARYEM ELBATOUL \n", + "34 EL HAMDAOUI NIZAR \n", + "35 AYALA GALLEGOS JAYDEN \n", + "36 GASHI AMRA \n", + "37 SICOLO FRANCESCO \n", + "38 DI MARCO ANITA \n", + "39 HYSENAJ ESLI \n", + "40 BILAL SHAMIR \n", + "41 LLESHI DANIEL \n", + "42 LORENZINI MARINA \n", + "43 LOTIERZO NICOLO' \n", + "44 MIRA TEO \n", + "45 VENTURINI AURORA \n", + "46 MION GINEVRA \n", + "47 NEZA REAN \n", + "48 PEDINI LILIANA \n", + "49 PEREZ PONCE ELLIE \n", + "50 CIRILLO JACOPO \n", + "51 BAR NICHOLAS \n", + "52 CUEL MATAN \n", + "53 POPESCU MATEI \n", + "54 PASCARELLA DOMENICO \n", + "55 CAMPARETTO ROCCA EDOARDO \n", + "56 FIORE LEONARDO \n", + "57 DE COL BEATRICE \n", + "58 SOTA PAOLA \n", + "59 TATARI SAUL \n", + "60 TRINCO ANITA \n", + "61 VALLAZZA ISABEL \n", + "62 MANGIALAIO LEON \n", + "63 WEGLEITER ENEAS \n", + "64 SAID ZAYD \n", + "65 RINDONE FILIPPO TOMMASO \n", + "66 BAH MAMADOU ADAMA \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 " + ] + }, + "execution_count": 177, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[[\"Cognome e nome bambino\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "8bae63ee", + "metadata": {}, + "outputs": [], + "source": [ + "#dfx = df[[\"Comune\", \"Cognome e nome bambino\",\"Codice fiscale\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"]]\n", + "dfout = pd.DataFrame(columns = [\"Comune\", \"Cognome e nome bambino\",\"Codice fiscale\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "342a6ed9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneCognome e nome bambinoCodice fiscaleOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Comune, Cognome e nome bambino, Codice fiscale, Ore contrattualizzate non erogate\n", + "ai sensi della delibera\n", + "n. 1025/2020]\n", + "Index: []" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 210, + "id": "75bbbfb7", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bingo\n" + ] + } + ], + "source": [ + "for ind in df.index:\n", + " if df[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"][ind] > 0:\n", + " if dfout.empty:\n", + " dfout = df.loc[[ind]]\n", + " else:\n", + " if df[\"Codice fiscale\"][ind] in dfout[\"Codice fiscale\"].values:\n", + " print(\"Bingo\")\n", + " continue\n", + " dfout = pd.concat([dfout, df.loc[[ind]]])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 211, + "id": "ba1b8d2a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26365935.2521.25956.502021-01-012021-12-31
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03184690.0030.75720.752021-01-012021-07-03
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02365965.5022.50988.002021-01-012021-12-31
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01117274.5039.00313.502021-09-062021-12-31
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06163592.0022.00614.002021-02-252021-08-06
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-023651269.7531.501301.252021-01-012021-12-31
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30151372.0020.00392.002021-03-022021-07-30
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171981010.5022.001032.502021-01-012021-07-17
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25176652.0030.00682.002021-01-012021-06-25
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-153651338.75110.001448.752021-01-012021-12-31
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31243812.2576.00888.252021-01-012021-08-31
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02183428.0020.00448.002021-01-012021-07-02
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02103474.5078.00552.502021-09-202021-12-31
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24236979.00110.001089.002021-01-012021-08-24
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-3189263.5058.50322.002021-10-042021-12-31
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-313651016.0060.001076.002021-01-012021-12-31
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31209488.0020.00508.002021-01-042021-07-31
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31212587.7523.50611.252021-01-012021-07-31
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04216573.0020.00593.002021-01-012021-08-04
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30211476.0020.00496.002021-01-012021-07-30
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27239469.5023.50493.002021-01-012021-08-27
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31243973.0095.001068.002021-01-012021-08-31
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01124493.5078.00571.502021-08-302021-12-31
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24236562.5022.50585.002021-01-012021-08-24
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06209950.7532.00982.752021-02-102021-09-06
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-313651405.0035.001440.002021-01-012021-12-31
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31212496.0020.00516.002021-01-012021-07-31
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-043651353.2532.501385.752021-01-012021-12-31
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-313651643.50132.001775.502021-01-012021-12-31
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03246695.0063.00758.002021-01-012021-09-03
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10253879.5021.25900.752021-01-012021-09-10
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-313651328.5025.001353.502021-01-012021-12-31
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-263651152.5066.001218.502021-01-012021-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "23 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "31 BOLZANO \n", + "34 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "53 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "60 BOLZANO \n", + "65 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "23 2020-08-17 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "31 2020-09-28 \n", + "34 2021-01-04 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "53 2020-06-01 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "60 2020-12-28 \n", + "65 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "23 2022-08-15 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "31 2022-08-31 \n", + "34 2021-07-31 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "53 2021-07-31 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "60 2023-08-31 \n", + "65 2022-08-26 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 365 \n", + "12 184 \n", + "13 365 \n", + "16 117 \n", + "17 163 \n", + "18 365 \n", + "19 151 \n", + "20 198 \n", + "21 176 \n", + "23 365 \n", + "25 243 \n", + "26 183 \n", + "27 103 \n", + "28 236 \n", + "29 89 \n", + "31 365 \n", + "34 209 \n", + "36 212 \n", + "37 216 \n", + "39 211 \n", + "40 239 \n", + "42 243 \n", + "43 124 \n", + "44 236 \n", + "46 209 \n", + "47 365 \n", + "53 212 \n", + "55 365 \n", + "56 365 \n", + "57 246 \n", + "58 253 \n", + "60 365 \n", + "65 365 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "12 690.00 \n", + "13 965.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "23 1338.75 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "31 1016.00 \n", + "34 488.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "39 476.00 \n", + "40 469.50 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "46 950.75 \n", + "47 1405.00 \n", + "53 496.00 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "60 1328.50 \n", + "65 1152.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "12 30.75 \n", + "13 22.50 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "23 110.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "31 60.00 \n", + "34 20.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "46 32.00 \n", + "47 35.00 \n", + "53 20.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "60 25.00 \n", + "65 66.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 968.25 2021-01-01 2021-12-31 \n", + "9 956.50 2021-01-01 2021-12-31 \n", + "12 720.75 2021-01-01 2021-07-03 \n", + "13 988.00 2021-01-01 2021-12-31 \n", + "16 313.50 2021-09-06 2021-12-31 \n", + "17 614.00 2021-02-25 2021-08-06 \n", + "18 1301.25 2021-01-01 2021-12-31 \n", + "19 392.00 2021-03-02 2021-07-30 \n", + "20 1032.50 2021-01-01 2021-07-17 \n", + "21 682.00 2021-01-01 2021-06-25 \n", + "23 1448.75 2021-01-01 2021-12-31 \n", + "25 888.25 2021-01-01 2021-08-31 \n", + "26 448.00 2021-01-01 2021-07-02 \n", + "27 552.50 2021-09-20 2021-12-31 \n", + "28 1089.00 2021-01-01 2021-08-24 \n", + "29 322.00 2021-10-04 2021-12-31 \n", + "31 1076.00 2021-01-01 2021-12-31 \n", + "34 508.00 2021-01-04 2021-07-31 \n", + "36 611.25 2021-01-01 2021-07-31 \n", + "37 593.00 2021-01-01 2021-08-04 \n", + "39 496.00 2021-01-01 2021-07-30 \n", + "40 493.00 2021-01-01 2021-08-27 \n", + "42 1068.00 2021-01-01 2021-08-31 \n", + "43 571.50 2021-08-30 2021-12-31 \n", + "44 585.00 2021-01-01 2021-08-24 \n", + "46 982.75 2021-02-10 2021-09-06 \n", + "47 1440.00 2021-01-01 2021-12-31 \n", + "53 516.00 2021-01-01 2021-07-31 \n", + "55 1385.75 2021-01-01 2021-12-31 \n", + "56 1775.50 2021-01-01 2021-12-31 \n", + "57 758.00 2021-01-01 2021-09-03 \n", + "58 900.75 2021-01-01 2021-09-10 \n", + "60 1353.50 2021-01-01 2021-12-31 \n", + "65 1218.50 2021-01-01 2021-12-31 " + ] + }, + "execution_count": 211, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "98dadca8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8Ajardi Josef0Ahrntal2019-10-02JRDJSF19R02B220YKirchler JudithSt. Peter In Ahrntal2020-02-242022-08-313651056.2524.001080.252021-01-012021-12-31
9Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-09-142020-12-3105.500.005.502021-01-012020-12-31
10Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-09-172021-06-29180289.5012.00301.502021-01-012021-06-29
11Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2021-09-062022-06-30117260.250.00260.252021-09-062021-12-31
12Feichter Robin0Ahrntal2019-08-27FCHRBN19M27B220NKammerlander VerenaAhrntal2021-10-192021-11-112415.250.0015.252021-10-192021-11-11
13Forer Mattis0Ahrntal2018-11-27FRRMTS18S27B220AKirchler IrmgardAhrntal2021-01-192021-08-31225287.258.00295.252021-01-192021-08-31
14Hofer Hanna0Ahrntal2018-09-05HFRHNN18P45B220DKirchler IrmgardAhrntal2020-09-142021-08-27239500.250.00500.252021-01-012021-08-27
15Hofer Julian0Ahrntal2020-04-16HFRJLN20D16B220PKirchler IrmgardAhrntal2020-08-132022-01-143651305.7522.001327.752021-01-012021-12-31
16Hofer Lukas0Ahrntal2019-05-31HFRLKS19E31B220NKirchler JudithSt. Peter In Ahrntal2021-11-172022-04-214550.250.0050.252021-11-172021-12-31
17Hopfgartner Toni0Ahrntal2018-01-31HPFTNO18A31B220PKammerlander VerenaAhrntal2019-02-112021-08-31243404.7516.00420.752021-01-012021-08-31
18Innerbichler Greta0Ahrntal2019-11-21NNRGRT19S61B220GKammerlander VerenaAhrntal2021-11-232020-12-31-32669.500.0069.502021-11-232020-12-31
19Innerbichler Jona0Ahrntal2019-06-03NNRJNO19H03B220WKirchler IrmgardAhrntal2021-11-022022-01-136073.000.0073.002021-11-022021-12-31
20Innerbichler Simon0Ahrntal2018-06-24NNRSMN18H24B220FKirchler JudithSt. Peter In Ahrntal2019-08-202021-09-06249756.0027.00783.002021-01-012021-09-06
21Kirchler Isabel0Ahrntal2018-02-07KRCSBL18B47B220NKammerlander VerenaAhrntal2019-01-022021-08-31243316.0012.00328.002021-01-012021-08-31
22Kirchler Lea Sophie0Ahrntal2020-02-29KRCLPH20B69B220IKirchler IrmgardAhrntal2021-09-082021-12-22106176.750.00176.752021-09-082021-12-22
23Lechner Lisa0Ahrntal2018-06-09LCHLSI18H49B220JKirchler ClaudiaSt. Jakob in Ahrntal2020-07-012021-08-31243347.5012.00359.502021-01-012021-08-31
24Mittermair Samu0Ahrntal2020-04-07MTTSMA20D07B220VKammerlander VerenaAhrntal2021-03-162020-12-31-74431.250.00431.252021-03-162020-12-31
25Niederwanger Liah0Ahrntal2020-02-23NDRLHI20B63B220QKammerlander VerenaAhrntal2021-09-062020-12-31-248155.250.00155.252021-09-062020-12-31
26Oberhauser Anton0Ahrntal2018-05-13BRHNTN18E13B220EKirchler IrmgardAhrntal2020-09-092021-08-31243735.000.00735.002021-01-012021-08-31
27Oberhofer Greta0Ahrntal2018-11-09BRHGRT18S49B220RKammerlander VerenaAhrntal2019-12-022021-08-31243364.0014.00378.002021-01-012021-08-31
28Oberlechner Emilia0Ahrntal2018-09-14BRLMLE18P54B220XKammerlander VerenaAhrntal2020-01-082021-08-31243599.5024.00623.502021-01-012021-08-31
29Obermair Theresa0Ahrntal2019-06-06BRMTRS19H46A952AKirchler JudithSt. Peter In Ahrntal2020-10-022022-08-30365863.0018.00881.002021-01-012021-12-31
30Obermair Tommi Jona0Ahrntal2019-06-07BRMTMJ19H07B220DKirchler ClaudiaSt. Jakob in Ahrntal2020-09-142020-12-310610.7512.00622.752021-01-012020-12-31
31Oberschmied Matilda0Ahrntal2019-08-07BRSMLD19M47B220BKirchler ClaudiaSt. Jakob in Ahrntal2020-09-092020-12-310884.000.00884.002021-01-012020-12-31
32Pareiner Jakob0Ahrntal2019-07-31PRNJKB19L31B220ZKirchler IrmgardAhrntal2020-10-052022-01-14365695.250.00695.252021-01-012021-12-31
33Ploner Greti0Ahrntal2018-04-23PLNGRT18D63B220AKirchler IrmgardAhrntal2019-08-192021-08-27239931.5010.50942.002021-01-012021-08-27
34Seeber Benjamin0Ahrntal2020-01-01SBRBJM20A01B220SKirchler IrmgardAhrntal2021-09-012021-12-22113250.000.00250.002021-09-012021-12-22
35Steger Elias0Ahrntal2018-03-19STGLSE18C19B220NKirchler IrmgardAhrntal2019-07-192021-08-26238601.5020.00621.502021-01-012021-08-26
36Steger Maximilian0Ahrntal2020-06-10STGMML20H10B220QKirchler ClaudiaSt. Jakob in Ahrntal2021-06-212020-12-31-171311.500.00311.502021-06-212020-12-31
37Steger Romy0Ahrntal2019-11-18STGRMY19S58B220DKirchler ClaudiaSt. Jakob in Ahrntal2021-05-112021-06-224354.750.0054.752021-05-112021-06-22
38Stolzlechner Clara0Ahrntal2018-01-02STLCLR18A42B220HKirchler JudithSt. Peter In Ahrntal2019-01-092021-09-06249553.2520.25573.502021-01-012021-09-06
39Timillero Liliane Giovanna0Ahrntal2021-04-15TMLLNG21D55B220DKammerlander VerenaAhrntal2021-09-062020-12-31-248220.750.00220.752021-09-062020-12-31
40Weger Maximilian0Ahrntal2020-06-24WGRMML20H24B220PKirchler ClaudiaSt. Jakob in Ahrntal2021-03-152020-12-31-73545.750.00545.752021-03-152020-12-31
41Weger Maximilian0Ahrntal2020-06-24WGRMML20H24B220PKirchler ClaudiaSt. Jakob in Ahrntal2021-09-062020-12-31-248190.750.00190.752021-09-062020-12-31
42Zimmerhofer Lio0Ahrntal2020-02-25ZMMLIO20B25Z102RKirchler IrmgardAhrntal2021-09-142021-12-23101165.500.00165.502021-09-142021-12-23
43Zimmerhofer Maja0Ahrntal2019-09-18ZMMMJA19P58B220BKirchler IrmgardAhrntal2021-08-112021-10-227397.500.0097.502021-08-112021-10-22
44Zoeschg Luzia0Ahrntal2020-05-09ZSCLZU20E49B220SKirchler JudithSt. Peter In Ahrntal2021-03-222020-12-31-80576.500.00576.502021-03-222020-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 Ajardi Josef 0 Ahrntal 2019-10-02 \n", + "9 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "10 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "11 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "12 Feichter Robin 0 Ahrntal 2019-08-27 \n", + "13 Forer Mattis 0 Ahrntal 2018-11-27 \n", + "14 Hofer Hanna 0 Ahrntal 2018-09-05 \n", + "15 Hofer Julian 0 Ahrntal 2020-04-16 \n", + "16 Hofer Lukas 0 Ahrntal 2019-05-31 \n", + "17 Hopfgartner Toni 0 Ahrntal 2018-01-31 \n", + "18 Innerbichler Greta 0 Ahrntal 2019-11-21 \n", + "19 Innerbichler Jona 0 Ahrntal 2019-06-03 \n", + "20 Innerbichler Simon 0 Ahrntal 2018-06-24 \n", + "21 Kirchler Isabel 0 Ahrntal 2018-02-07 \n", + "22 Kirchler Lea Sophie 0 Ahrntal 2020-02-29 \n", + "23 Lechner Lisa 0 Ahrntal 2018-06-09 \n", + "24 Mittermair Samu 0 Ahrntal 2020-04-07 \n", + "25 Niederwanger Liah 0 Ahrntal 2020-02-23 \n", + "26 Oberhauser Anton 0 Ahrntal 2018-05-13 \n", + "27 Oberhofer Greta 0 Ahrntal 2018-11-09 \n", + "28 Oberlechner Emilia 0 Ahrntal 2018-09-14 \n", + "29 Obermair Theresa 0 Ahrntal 2019-06-06 \n", + "30 Obermair Tommi Jona 0 Ahrntal 2019-06-07 \n", + "31 Oberschmied Matilda 0 Ahrntal 2019-08-07 \n", + "32 Pareiner Jakob 0 Ahrntal 2019-07-31 \n", + "33 Ploner Greti 0 Ahrntal 2018-04-23 \n", + "34 Seeber Benjamin 0 Ahrntal 2020-01-01 \n", + "35 Steger Elias 0 Ahrntal 2018-03-19 \n", + "36 Steger Maximilian 0 Ahrntal 2020-06-10 \n", + "37 Steger Romy 0 Ahrntal 2019-11-18 \n", + "38 Stolzlechner Clara 0 Ahrntal 2018-01-02 \n", + "39 Timillero Liliane Giovanna 0 Ahrntal 2021-04-15 \n", + "40 Weger Maximilian 0 Ahrntal 2020-06-24 \n", + "41 Weger Maximilian 0 Ahrntal 2020-06-24 \n", + "42 Zimmerhofer Lio 0 Ahrntal 2020-02-25 \n", + "43 Zimmerhofer Maja 0 Ahrntal 2019-09-18 \n", + "44 Zoeschg Luzia 0 Ahrntal 2020-05-09 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 JRDJSF19R02B220Y Kirchler Judith \n", + "9 DRNDLA19A46Z131E Kirchler Claudia \n", + "10 DRNDLA19A46Z131E Kirchler Claudia \n", + "11 DRNDLA19A46Z131E Kirchler Claudia \n", + "12 FCHRBN19M27B220N Kammerlander Verena \n", + "13 FRRMTS18S27B220A Kirchler Irmgard \n", + "14 HFRHNN18P45B220D Kirchler Irmgard \n", + "15 HFRJLN20D16B220P Kirchler Irmgard \n", + "16 HFRLKS19E31B220N Kirchler Judith \n", + "17 HPFTNO18A31B220P Kammerlander Verena \n", + "18 NNRGRT19S61B220G Kammerlander Verena \n", + "19 NNRJNO19H03B220W Kirchler Irmgard \n", + "20 NNRSMN18H24B220F Kirchler Judith \n", + "21 KRCSBL18B47B220N Kammerlander Verena \n", + "22 KRCLPH20B69B220I Kirchler Irmgard \n", + "23 LCHLSI18H49B220J Kirchler Claudia \n", + "24 MTTSMA20D07B220V Kammerlander Verena \n", + "25 NDRLHI20B63B220Q Kammerlander Verena \n", + "26 BRHNTN18E13B220E Kirchler Irmgard \n", + "27 BRHGRT18S49B220R Kammerlander Verena \n", + "28 BRLMLE18P54B220X Kammerlander Verena \n", + "29 BRMTRS19H46A952A Kirchler Judith \n", + "30 BRMTMJ19H07B220D Kirchler Claudia \n", + "31 BRSMLD19M47B220B Kirchler Claudia \n", + "32 PRNJKB19L31B220Z Kirchler Irmgard \n", + "33 PLNGRT18D63B220A Kirchler Irmgard \n", + "34 SBRBJM20A01B220S Kirchler Irmgard \n", + "35 STGLSE18C19B220N Kirchler Irmgard \n", + "36 STGMML20H10B220Q Kirchler Claudia \n", + "37 STGRMY19S58B220D Kirchler Claudia \n", + "38 STLCLR18A42B220H Kirchler Judith \n", + "39 TMLLNG21D55B220D Kammerlander Verena \n", + "40 WGRMML20H24B220P Kirchler Claudia \n", + "41 WGRMML20H24B220P Kirchler Claudia \n", + "42 ZMMLIO20B25Z102R Kirchler Irmgard \n", + "43 ZMMMJA19P58B220B Kirchler Irmgard \n", + "44 ZSCLZU20E49B220S Kirchler Judith \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 St. Peter In Ahrntal \n", + "9 St. Jakob in Ahrntal \n", + "10 St. Jakob in Ahrntal \n", + "11 St. Jakob in Ahrntal \n", + "12 Ahrntal \n", + "13 Ahrntal \n", + "14 Ahrntal \n", + "15 Ahrntal \n", + "16 St. Peter In Ahrntal \n", + "17 Ahrntal \n", + "18 Ahrntal \n", + "19 Ahrntal \n", + "20 St. Peter In Ahrntal \n", + "21 Ahrntal \n", + "22 Ahrntal \n", + "23 St. Jakob in Ahrntal \n", + "24 Ahrntal \n", + "25 Ahrntal \n", + "26 Ahrntal \n", + "27 Ahrntal \n", + "28 Ahrntal \n", + "29 St. Peter In Ahrntal \n", + "30 St. Jakob in Ahrntal \n", + "31 St. Jakob in Ahrntal \n", + "32 Ahrntal \n", + "33 Ahrntal \n", + "34 Ahrntal \n", + "35 Ahrntal \n", + "36 St. Jakob in Ahrntal \n", + "37 St. Jakob in Ahrntal \n", + "38 St. Peter In Ahrntal \n", + "39 Ahrntal \n", + "40 St. Jakob in Ahrntal \n", + "41 St. Jakob in Ahrntal \n", + "42 Ahrntal \n", + "43 Ahrntal \n", + "44 St. Peter In Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-02-24 \n", + "9 2020-09-14 \n", + "10 2020-09-17 \n", + "11 2021-09-06 \n", + "12 2021-10-19 \n", + "13 2021-01-19 \n", + "14 2020-09-14 \n", + "15 2020-08-13 \n", + "16 2021-11-17 \n", + "17 2019-02-11 \n", + "18 2021-11-23 \n", + "19 2021-11-02 \n", + "20 2019-08-20 \n", + "21 2019-01-02 \n", + "22 2021-09-08 \n", + "23 2020-07-01 \n", + "24 2021-03-16 \n", + "25 2021-09-06 \n", + "26 2020-09-09 \n", + "27 2019-12-02 \n", + "28 2020-01-08 \n", + "29 2020-10-02 \n", + "30 2020-09-14 \n", + "31 2020-09-09 \n", + "32 2020-10-05 \n", + "33 2019-08-19 \n", + "34 2021-09-01 \n", + "35 2019-07-19 \n", + "36 2021-06-21 \n", + "37 2021-05-11 \n", + "38 2019-01-09 \n", + "39 2021-09-06 \n", + "40 2021-03-15 \n", + "41 2021-09-06 \n", + "42 2021-09-14 \n", + "43 2021-08-11 \n", + "44 2021-03-22 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2020-12-31 \n", + "10 2021-06-29 \n", + "11 2022-06-30 \n", + "12 2021-11-11 \n", + "13 2021-08-31 \n", + "14 2021-08-27 \n", + "15 2022-01-14 \n", + "16 2022-04-21 \n", + "17 2021-08-31 \n", + "18 2020-12-31 \n", + "19 2022-01-13 \n", + "20 2021-09-06 \n", + "21 2021-08-31 \n", + "22 2021-12-22 \n", + "23 2021-08-31 \n", + "24 2020-12-31 \n", + "25 2020-12-31 \n", + "26 2021-08-31 \n", + "27 2021-08-31 \n", + "28 2021-08-31 \n", + "29 2022-08-30 \n", + "30 2020-12-31 \n", + "31 2020-12-31 \n", + "32 2022-01-14 \n", + "33 2021-08-27 \n", + "34 2021-12-22 \n", + "35 2021-08-26 \n", + "36 2020-12-31 \n", + "37 2021-06-22 \n", + "38 2021-09-06 \n", + "39 2020-12-31 \n", + "40 2020-12-31 \n", + "41 2020-12-31 \n", + "42 2021-12-23 \n", + "43 2021-10-22 \n", + "44 2020-12-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 0 \n", + "10 180 \n", + "11 117 \n", + "12 24 \n", + "13 225 \n", + "14 239 \n", + "15 365 \n", + "16 45 \n", + "17 243 \n", + "18 -326 \n", + "19 60 \n", + "20 249 \n", + "21 243 \n", + "22 106 \n", + "23 243 \n", + "24 -74 \n", + "25 -248 \n", + "26 243 \n", + "27 243 \n", + "28 243 \n", + "29 365 \n", + "30 0 \n", + "31 0 \n", + "32 365 \n", + "33 239 \n", + "34 113 \n", + "35 238 \n", + "36 -171 \n", + "37 43 \n", + "38 249 \n", + "39 -248 \n", + "40 -73 \n", + "41 -248 \n", + "42 101 \n", + "43 73 \n", + "44 -80 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1056.25 \n", + "9 5.50 \n", + "10 289.50 \n", + "11 260.25 \n", + "12 15.25 \n", + "13 287.25 \n", + "14 500.25 \n", + "15 1305.75 \n", + "16 50.25 \n", + "17 404.75 \n", + "18 69.50 \n", + "19 73.00 \n", + "20 756.00 \n", + "21 316.00 \n", + "22 176.75 \n", + "23 347.50 \n", + "24 431.25 \n", + "25 155.25 \n", + "26 735.00 \n", + "27 364.00 \n", + "28 599.50 \n", + "29 863.00 \n", + "30 610.75 \n", + "31 884.00 \n", + "32 695.25 \n", + "33 931.50 \n", + "34 250.00 \n", + "35 601.50 \n", + "36 311.50 \n", + "37 54.75 \n", + "38 553.25 \n", + "39 220.75 \n", + "40 545.75 \n", + "41 190.75 \n", + "42 165.50 \n", + "43 97.50 \n", + "44 576.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 24.00 \n", + "9 0.00 \n", + "10 12.00 \n", + "11 0.00 \n", + "12 0.00 \n", + "13 8.00 \n", + "14 0.00 \n", + "15 22.00 \n", + "16 0.00 \n", + "17 16.00 \n", + "18 0.00 \n", + "19 0.00 \n", + "20 27.00 \n", + "21 12.00 \n", + "22 0.00 \n", + "23 12.00 \n", + "24 0.00 \n", + "25 0.00 \n", + "26 0.00 \n", + "27 14.00 \n", + "28 24.00 \n", + "29 18.00 \n", + "30 12.00 \n", + "31 0.00 \n", + "32 0.00 \n", + "33 10.50 \n", + "34 0.00 \n", + "35 20.00 \n", + "36 0.00 \n", + "37 0.00 \n", + "38 20.25 \n", + "39 0.00 \n", + "40 0.00 \n", + "41 0.00 \n", + "42 0.00 \n", + "43 0.00 \n", + "44 0.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 1080.25 2021-01-01 2021-12-31 \n", + "9 5.50 2021-01-01 2020-12-31 \n", + "10 301.50 2021-01-01 2021-06-29 \n", + "11 260.25 2021-09-06 2021-12-31 \n", + "12 15.25 2021-10-19 2021-11-11 \n", + "13 295.25 2021-01-19 2021-08-31 \n", + "14 500.25 2021-01-01 2021-08-27 \n", + "15 1327.75 2021-01-01 2021-12-31 \n", + "16 50.25 2021-11-17 2021-12-31 \n", + "17 420.75 2021-01-01 2021-08-31 \n", + "18 69.50 2021-11-23 2020-12-31 \n", + "19 73.00 2021-11-02 2021-12-31 \n", + "20 783.00 2021-01-01 2021-09-06 \n", + "21 328.00 2021-01-01 2021-08-31 \n", + "22 176.75 2021-09-08 2021-12-22 \n", + "23 359.50 2021-01-01 2021-08-31 \n", + "24 431.25 2021-03-16 2020-12-31 \n", + "25 155.25 2021-09-06 2020-12-31 \n", + "26 735.00 2021-01-01 2021-08-31 \n", + "27 378.00 2021-01-01 2021-08-31 \n", + "28 623.50 2021-01-01 2021-08-31 \n", + "29 881.00 2021-01-01 2021-12-31 \n", + "30 622.75 2021-01-01 2020-12-31 \n", + "31 884.00 2021-01-01 2020-12-31 \n", + "32 695.25 2021-01-01 2021-12-31 \n", + "33 942.00 2021-01-01 2021-08-27 \n", + "34 250.00 2021-09-01 2021-12-22 \n", + "35 621.50 2021-01-01 2021-08-26 \n", + "36 311.50 2021-06-21 2020-12-31 \n", + "37 54.75 2021-05-11 2021-06-22 \n", + "38 573.50 2021-01-01 2021-09-06 \n", + "39 220.75 2021-09-06 2020-12-31 \n", + "40 545.75 2021-03-15 2020-12-31 \n", + "41 190.75 2021-09-06 2020-12-31 \n", + "42 165.50 2021-09-14 2021-12-23 \n", + "43 97.50 2021-08-11 2021-10-22 \n", + "44 576.50 2021-03-22 2020-12-31 " + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ffeecee", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "3e8abe8d", + "metadata": {}, + "source": [ + "## Vecchio metodo" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "4acf4374", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre di assistenza \\n ai sensi della delibera\\nn. 666/2019
0Bolzano59
\n", + "
" + ], + "text/plain": [ + " Comune Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\n", + "0 Bolzano 59 " + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.groupby(\"Comune\", as_index=False)[\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\"\n", + " ].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "cdd9c198", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019
Comune
Bolzano59
\n", + "
" + ], + "text/plain": [ + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\n", + "Comune \n", + "Bolzano 59 " + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.groupby([\"Comune\"]).agg({\"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\":\"count\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "id": "71b02919", + "metadata": {}, + "outputs": [], + "source": [ + "#c = df[\"Codice fiscale\"].unique\n", + "dfx = df.drop_duplicates(subset = [\"Codice fiscale\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "id": "ea1a0a2d", + "metadata": {}, + "outputs": [], + "source": [ + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0" + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "id": "0db71170", + "metadata": {}, + "outputs": [], + "source": [ + " df2bis = dfx[c].groupby(\"Comune\", as_index=False)[\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"\n", + " ].apply(lambda x: x[x > 0].sum())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "634575da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
0Bolzano1612.75
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Bolzano \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \n", + "0 1612.75 " + ] + }, + "execution_count": 223, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2bis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "129075cb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 207, + "id": "8e1896c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "34" + ] + }, + "execution_count": 207, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#dfx = df.groupby(\"Codice fiscale\", as_index = False)\n", + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0\n", + "len(dfx[c])" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "id": "2d98620d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26935.2521.25956.50
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01605.500.00605.50
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0884.000.0084.00
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03690.0030.75720.75
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02965.5022.50988.00
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17462.500.00462.50
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-311314.500.001314.50
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01274.5039.00313.50
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06592.0022.00614.00
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-021269.7531.501301.25
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30372.0020.00392.00
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171010.5022.001032.50
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25652.0030.00682.00
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29940.500.00940.50
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-151338.75110.001448.75
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28575.500.00575.50
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31812.2576.00888.25
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02428.0020.00448.00
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02474.5078.00552.50
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24979.00110.001089.00
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-31263.5058.50322.00
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31806.500.00806.50
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-311016.0060.001076.00
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02616.000.00616.00
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-1795.000.0095.00
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31488.0020.00508.00
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-30140.000.00140.00
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31587.7523.50611.25
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04573.0020.00593.00
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-281211.750.001211.75
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30476.0020.00496.00
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27469.5023.50493.00
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02200.250.00200.25
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31973.0095.001068.00
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01493.5078.00571.50
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24562.5022.50585.00
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16427.250.00427.25
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06950.7532.00982.75
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-311405.0035.001440.00
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08632.500.00632.50
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-01248.250.00248.25
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-30213.000.00213.00
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31543.750.00543.75
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31706.000.00706.00
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31496.0020.00516.00
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-17108.500.00108.50
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-041353.2532.501385.75
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-311643.50132.001775.50
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03695.0063.00758.00
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10879.5021.25900.75
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-02276.000.00276.00
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-311328.5025.001353.50
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30543.000.00543.00
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01401.500.00401.50
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-311734.000.001734.00
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02629.500.00629.50
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-261152.5066.001218.50
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "9 956.50 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 720.75 \n", + "13 988.00 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 313.50 \n", + "17 614.00 \n", + "18 1301.25 \n", + "19 392.00 \n", + "20 1032.50 \n", + "21 682.00 \n", + "22 940.50 \n", + "23 1448.75 \n", + "24 575.50 \n", + "25 888.25 \n", + "26 448.00 \n", + "27 552.50 \n", + "28 1089.00 \n", + "29 322.00 \n", + "30 806.50 \n", + "31 1076.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 508.00 \n", + "35 140.00 \n", + "36 611.25 \n", + "37 593.00 \n", + "38 1211.75 \n", + "39 496.00 \n", + "40 493.00 \n", + "41 200.25 \n", + "42 1068.00 \n", + "43 571.50 \n", + "44 585.00 \n", + "45 427.25 \n", + "46 982.75 \n", + "47 1440.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 516.00 \n", + "54 108.50 \n", + "55 1385.75 \n", + "56 1775.50 \n", + "57 758.00 \n", + "58 900.75 \n", + "59 276.00 \n", + "60 1353.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1218.50 " + ] + }, + "execution_count": 202, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "a0f879dc", + "metadata": {}, + "outputs": [], + "source": [ + "df2 = df[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"].notnull()\n", + "df2 = df[c].groupby(\"Comune\", as_index = False)[\"Codice fiscale\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "7fb21c72", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneCodice fiscale
0Bolzano34
\n", + "
" + ], + "text/plain": [ + " Comune Codice fiscale\n", + "0 Bolzano 34" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38880426", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/.ipynb_checkpoints/ErroreProportionMAximalStunden-checkpoint.ipynb b/pages/.ipynb_checkpoints/ErroreProportionMAximalStunden-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..c29f52691c2a0af13d41580390a3cb92175ae468 --- /dev/null +++ b/pages/.ipynb_checkpoints/ErroreProportionMAximalStunden-checkpoint.ipynb @@ -0,0 +1,2293 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Erklärung Gemeinden Jahr 2020 Tramin.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c74655a1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0Unnamed: 1Unnamed: 2Unnamed: 3Abrechnung für den Tagesmütter- / Tagesväterdienst - Jahr 2020Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9Unnamed: 10Unnamed: 11Unnamed: 12
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Trägerkörperschaft:NaNNaNSozialgenossenschaft Mit Bäuerinnen lernen-wac...NaNNaNNaNNaNNaNNaNNaNNaNNaN
3Wohnsitzgemeinde bzg. Gemeinde des ständigen A...NaNNaNTraminNaNNaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
7Fortlaufende\\nNummerNachname und Vorname des KindesGeburtsdatumSteuernummerTagesmutterWohnsitzgemeinde der TagesmutterDatum Vertragsbeginn (oder Datum Beginn der Be...Datum Vertragsende \\n(oder Datum Ende der Betr...Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt
81Chirone Riccardo2018-10-09 00:00:00CHRRCR18R09E986OSalvadori PaolaBozen2019-11-19 00:00:00NaN1308.7589.5NaN-3401058.25
92Frei Juri2018-05-29 00:00:00FREJRU18E29A952RPeer PetraKurtatsch2020-03-10 00:00:002020-05-05 00:00:00090NaN090
103Kajana Mia2018-08-03 00:00:00KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-18 00:00:00NaN559.524NaN-1.75581.75
113Kajana Mia2018-08-03 00:00:00KJNMIA18M43A952AAmbach MariaEppan2019-08-06 00:00:002020-05-04 00:00:0099.5144.75NaN66.25310.5
124Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NAmbach MariaEppan2020-08-17 00:00:002020-08-28 00:00:0071.50NaN071.5
134Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NHuber MelanieMargreid2020-11-25 00:00:002020-11-27 00:00:0026.50NaN026.5
144Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NPeer PetraKurtatsch2020-01-02 00:00:002020-05-06 00:00:00189.75270.5NaN332.5792.75
154Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NPeer PetraKurtatsch2020-07-20 00:00:00NaN80410.25NaN0814.25
165Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2020-07-20 00:00:002020-11-23 00:00:00231.520.75NaN0252.25
175Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2019-11-25 00:00:002020-05-06 00:00:00173.5279.5NaN364.5817.5
186Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-07-06 00:00:00NaN390.7520NaN0410.75
196Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PPeer PetraKurtatsch2020-02-03 00:00:002020-05-06 00:00:0055120NaN50225
206Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-02-07 00:00:002020-02-08 00:00:004.50NaN04.5
216Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-09-04 00:00:002020-09-04 00:00:0080NaN08
226Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-08-21 00:00:002020-08-21 00:00:0070NaN07
236Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-03-02 00:00:002020-03-04 00:00:00150NaN015
246Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-05-18 00:00:002020-06-18 00:00:0074.750NaN074.75
25NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
26NaNNaNNaNNaNNaNNaNNaNSumme4019.51069.250471.55560.25
27NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
28NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
29NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
30NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
31NaNDieser Jahresbericht entspricht dem Original, ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
32NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
33NaNUnterschrift des/der gesetzlichen Vertreters/i...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
34NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
35NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
36NaN* bei eventuellen Betreuungsverträgen, welche ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Trägerkörperschaft: \n", + "3 Wohnsitzgemeinde bzg. Gemeinde des ständigen A... \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Fortlaufende\\nNummer \n", + "8 1 \n", + "9 2 \n", + "10 3 \n", + "11 3 \n", + "12 4 \n", + "13 4 \n", + "14 4 \n", + "15 4 \n", + "16 5 \n", + "17 5 \n", + "18 6 \n", + "19 6 \n", + "20 6 \n", + "21 6 \n", + "22 6 \n", + "23 6 \n", + "24 6 \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 NaN NaN \n", + "5 NaN NaN \n", + "6 NaN NaN \n", + "7 Nachname und Vorname des Kindes Geburtsdatum \n", + "8 Chirone Riccardo 2018-10-09 00:00:00 \n", + "9 Frei Juri 2018-05-29 00:00:00 \n", + "10 Kajana Mia 2018-08-03 00:00:00 \n", + "11 Kajana Mia 2018-08-03 00:00:00 \n", + "12 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "13 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "14 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "15 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "16 Von Call Dylan 2019-02-19 00:00:00 \n", + "17 Von Call Dylan 2019-02-19 00:00:00 \n", + "18 Zelger Samuel 2018-05-08 00:00:00 \n", + "19 Zelger Samuel 2018-05-08 00:00:00 \n", + "20 Zelger Samuel 2018-05-08 00:00:00 \n", + "21 Zelger Samuel 2018-05-08 00:00:00 \n", + "22 Zelger Samuel 2018-05-08 00:00:00 \n", + "23 Zelger Samuel 2018-05-08 00:00:00 \n", + "24 Zelger Samuel 2018-05-08 00:00:00 \n", + "25 NaN NaN \n", + "26 NaN NaN \n", + "27 NaN NaN \n", + "28 NaN NaN \n", + "29 NaN NaN \n", + "30 NaN NaN \n", + "31 Dieser Jahresbericht entspricht dem Original, ... NaN \n", + "32 NaN NaN \n", + "33 Unterschrift des/der gesetzlichen Vertreters/i... NaN \n", + "34 NaN NaN \n", + "35 NaN NaN \n", + "36 * bei eventuellen Betreuungsverträgen, welche ... NaN \n", + "\n", + " Unnamed: 3 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Sozialgenossenschaft Mit Bäuerinnen lernen-wac... \n", + "3 Tramin \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Steuernummer \n", + "8 CHRRCR18R09E986O \n", + "9 FREJRU18E29A952R \n", + "10 KJNMIA18M43A952A \n", + "11 KJNMIA18M43A952A \n", + "12 TMGMRM19B41A952N \n", + "13 TMGMRM19B41A952N \n", + "14 TMGMRM19B41A952N \n", + "15 TMGMRM19B41A952N \n", + "16 VNCDLN19B19A952G \n", + "17 VNCDLN19B19A952G \n", + "18 ZLGSML18E08F132P \n", + "19 ZLGSML18E08F132P \n", + "20 ZLGSML18E08F132P \n", + "21 ZLGSML18E08F132P \n", + "22 ZLGSML18E08F132P \n", + "23 ZLGSML18E08F132P \n", + "24 ZLGSML18E08F132P \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Abrechnung für den Tagesmütter- / Tagesväterdienst - Jahr 2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Tagesmutter \n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 5 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Wohnsitzgemeinde der Tagesmutter \n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 6 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsbeginn (oder Datum Beginn der Be... \n", + "8 2019-11-19 00:00:00 \n", + "9 2020-03-10 00:00:00 \n", + "10 2020-05-18 00:00:00 \n", + "11 2019-08-06 00:00:00 \n", + "12 2020-08-17 00:00:00 \n", + "13 2020-11-25 00:00:00 \n", + "14 2020-01-02 00:00:00 \n", + "15 2020-07-20 00:00:00 \n", + "16 2020-07-20 00:00:00 \n", + "17 2019-11-25 00:00:00 \n", + "18 2020-07-06 00:00:00 \n", + "19 2020-02-03 00:00:00 \n", + "20 2020-02-07 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "23 2020-03-02 00:00:00 \n", + "24 2020-05-18 00:00:00 \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 7 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsende \\n(oder Datum Ende der Betr... \n", + "8 NaN \n", + "9 2020-05-05 00:00:00 \n", + "10 NaN \n", + "11 2020-05-04 00:00:00 \n", + "12 2020-08-28 00:00:00 \n", + "13 2020-11-27 00:00:00 \n", + "14 2020-05-06 00:00:00 \n", + "15 NaN \n", + "16 2020-11-23 00:00:00 \n", + "17 2020-05-06 00:00:00 \n", + "18 NaN \n", + "19 2020-05-06 00:00:00 \n", + "20 2020-02-08 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "23 2020-03-04 00:00:00 \n", + "24 2020-06-18 00:00:00 \n", + "25 NaN \n", + "26 Summe \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 8 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666... \n", + "8 1308.75 \n", + "9 0 \n", + "10 559.5 \n", + "11 99.5 \n", + "12 71.5 \n", + "13 26.5 \n", + "14 189.75 \n", + "15 804 \n", + "16 231.5 \n", + "17 173.5 \n", + "18 390.75 \n", + "19 55 \n", + "20 4.5 \n", + "21 8 \n", + "22 7 \n", + "23 15 \n", + "24 74.75 \n", + "25 NaN \n", + "26 4019.5 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 9 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 89.5 \n", + "9 90 \n", + "10 24 \n", + "11 144.75 \n", + "12 0 \n", + "13 0 \n", + "14 270.5 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.5 \n", + "18 20 \n", + "19 120 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 NaN \n", + "26 1069.25 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 10 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 NaN \n", + "9 NaN \n", + "10 NaN \n", + "11 NaN \n", + "12 NaN \n", + "13 NaN \n", + "14 NaN \n", + "15 NaN \n", + "16 NaN \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "20 NaN \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 0 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 11 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 -340 \n", + "9 0 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0 \n", + "13 0 \n", + "14 332.5 \n", + "15 0 \n", + "16 0 \n", + "17 364.5 \n", + "18 0 \n", + "19 50 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 NaN \n", + "26 471.5 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 12 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt \n", + "8 1058.25 \n", + "9 90 \n", + "10 581.75 \n", + "11 310.5 \n", + "12 71.5 \n", + "13 26.5 \n", + "14 792.75 \n", + "15 814.25 \n", + "16 252.25 \n", + "17 817.5 \n", + "18 410.75 \n", + "19 225 \n", + "20 4.5 \n", + "21 8 \n", + "22 7 \n", + "23 15 \n", + "24 74.75 \n", + "25 NaN \n", + "26 5560.25 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Trägerkörperschaft: \n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale Sozialgenossenschaft Mit Bäuerinnen lernen-wac...\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) NaN\n", + "Ore totali rendicontate per il 2020 NaN\n", + "Name: 2, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f5ad0313", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = traeger[3].title()\n", + "gemeinde = df.iloc[3]\n", + "gemeinde = gemeinde[3]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "818d8c8d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Tramin'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "62d5bd44", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + " cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + " df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + " df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + " df = df[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "4065589c", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (1409479787.py, line 1)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Input \u001b[0;32mIn [21]\u001b[0;36m\u001b[0m\n\u001b[0;31m if df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains(\"bozen\" OR \"eppan\"):\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "if df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains(\"bozen\" OR \"eppan\"):\n", + " print('xxx')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2020" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "af6a6cf6", + "metadata": {}, + "outputs": [], + "source": [ + " condizioneerrore = ((1920 * (df[\"GiorniAssistenzaAnnoRiferimento\"])) / 366) < df[\n", + " \"Ore totali rendicontate per il 2020\"\n", + " ]\n", + " \n", + " condizioneerrore2 = ((1920 * (df.groupby(\"Codice fiscale\")[\"GiorniAssistenzaAnnoRiferimento\"].transform(\"sum\")) / 366)) < df.groupby(\"Codice fiscale\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\")" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "08e4a7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "VNCDLN19B19A952G\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n" + ] + } + ], + "source": [ + "for i in df[condizioneerrore][\"Codice fiscale\"]:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "29ed03dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-313661308.7589.500-340.001058.252020-01-012020-12-31
9Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-102020-05-05570.0090.0000.0090.002020-03-102020-05-05
10Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-182020-12-31228559.5024.000-1.75581.752020-05-182020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-0412599.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.0071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-27326.500.0000.0026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-06126189.75270.500332.50792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-31165804.0010.2500.00814.252020-07-202020-12-31
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-23127231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-06127173.50279.500364.50817.502020-01-012020-05-06
18Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-062020-12-31179390.7520.0000.00410.752020-07-062020-12-31
19Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-032020-05-069455.00120.00050.00225.002020-02-032020-05-06
20Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-072020-02-0824.500.0000.004.502020-02-072020-02-08
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-0418.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-2117.000.0000.007.002020-08-212020-08-21
23Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-022020-03-04315.000.0000.0015.002020-03-022020-03-04
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-183274.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "18 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "19 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "20 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "23 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "9 Tramin 2018-05-29 FREJRU18E29A952R \n", + "10 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "18 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "19 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "20 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "23 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "9 2020-03-10 \n", + "10 2020-05-18 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "18 2020-07-06 \n", + "19 2020-02-03 \n", + "20 2020-02-07 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-02 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "9 2020-05-05 \n", + "10 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "18 2020-12-31 \n", + "19 2020-05-06 \n", + "20 2020-02-08 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-04 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 366 \n", + "9 57 \n", + "10 228 \n", + "11 125 \n", + "12 12 \n", + "13 3 \n", + "14 126 \n", + "15 165 \n", + "16 127 \n", + "17 127 \n", + "18 179 \n", + "19 94 \n", + "20 2 \n", + "21 1 \n", + "22 1 \n", + "23 3 \n", + "24 32 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "9 0.00 \n", + "10 559.50 \n", + "11 99.50 \n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "16 231.50 \n", + "17 173.50 \n", + "18 390.75 \n", + "19 55.00 \n", + "20 4.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "23 15.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "9 90.00 \n", + "10 24.00 \n", + "11 144.75 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.50 \n", + "18 20.00 \n", + "19 120.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "9 0.00 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 332.50 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "18 0.00 \n", + "19 50.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "9 90.00 2020-03-10 2020-05-05 \n", + "10 581.75 2020-05-18 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "18 410.75 2020-07-06 2020-12-31 \n", + "19 225.00 2020-02-03 2020-05-06 \n", + "20 4.50 2020-02-07 2020-02-08 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "23 15.00 2020-03-02 2020-03-04 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9f22c6d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/.ipynb_checkpoints/covid4_gemeinden-checkpoint.ipynb b/pages/.ipynb_checkpoints/covid4_gemeinden-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..bd03c73a1856194b2ff896382a28d5d377c7fe90 --- /dev/null +++ b/pages/.ipynb_checkpoints/covid4_gemeinden-checkpoint.ipynb @@ -0,0 +1,2211 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 118, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "import copy\n", + "import openpyxl\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"errori dopo modifica 2021 - Copy.xlsx\"\n", + "#fn = \"Erklärung Gemeinden Jahr 2020 Tramin.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn, sheet_name = 'ita',engine = 'openpyxl')#, skiprows = 8)\n", + "#df = pd.read_excel(fn,engine = 'openpyxl')#, skiprows = 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "e2c1e874", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2021Unnamed: 1Unnamed: 2Unnamed: 3Unnamed: 4Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9Unnamed: 10Unnamed: 11
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1Ente gestore:NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Casa BimboNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Comune di residenza o di stabile dimora dei ba...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4BolzanoNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
.......................................
87NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
88NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
89NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
90NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
91NaNNaNNaNNaNNaNNaNNaNNaNNaN40952.251612.7542565
\n", + "

92 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2021 \\\n", + "0 NaN \n", + "1 Ente gestore: \n", + "2 Casa Bimbo \n", + "3 Comune di residenza o di stabile dimora dei ba... \n", + "4 Bolzano \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 Unnamed: 3 Unnamed: 4 Unnamed: 5 Unnamed: 6 \\\n", + "0 NaN NaN NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN NaN NaN \n", + ".. ... ... ... ... ... ... \n", + "87 NaN NaN NaN NaN NaN NaN \n", + "88 NaN NaN NaN NaN NaN NaN \n", + "89 NaN NaN NaN NaN NaN NaN \n", + "90 NaN NaN NaN NaN NaN NaN \n", + "91 NaN NaN NaN NaN NaN NaN \n", + "\n", + " Unnamed: 7 Unnamed: 8 Unnamed: 9 Unnamed: 10 Unnamed: 11 \n", + "0 NaN NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN NaN \n", + ".. ... ... ... ... ... \n", + "87 NaN NaN NaN NaN 0 \n", + "88 NaN NaN NaN NaN 0 \n", + "89 NaN NaN NaN NaN 0 \n", + "90 NaN NaN NaN NaN 0 \n", + "91 NaN NaN 40952.25 1612.75 42565 \n", + "\n", + "[92 rows x 12 columns]" + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " #\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\",\n", + " #\"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2021\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "id": "6f06a836", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,\"Cognome e nome bambino\", df[\"Cognome\"] + ' ' + df[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "id": "b44721c6", + "metadata": {}, + "outputs": [], + "source": [ + "df.drop([\"Cognome\",\"Nome\"], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "id": "3bac24f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1Ente gestore:NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Casa BimboNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Comune di residenza o di stabile dimora dei ba...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4BolzanoNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
....................................
87NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
88NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
89NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
90NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
91NaNNaNNaNNaNNaNNaNNaNNaN40952.251612.7542565
\n", + "

92 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino \\\n", + "0 NaN NaN \n", + "1 Ente gestore: NaN \n", + "2 Casa Bimbo NaN \n", + "3 Comune di residenza o di stabile dimora dei ba... NaN \n", + "4 Bolzano NaN \n", + ".. ... ... \n", + "87 NaN NaN \n", + "88 NaN NaN \n", + "89 NaN NaN \n", + "90 NaN NaN \n", + "91 NaN NaN \n", + "\n", + " Data di nascita Codice fiscale Assistente domiciliare all'infanzia \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 NaN NaN NaN \n", + ".. ... ... ... \n", + "87 NaN NaN NaN \n", + "88 NaN NaN NaN \n", + "89 NaN NaN NaN \n", + "90 NaN NaN NaN \n", + "91 NaN NaN NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 40952.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 1612.75 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 0 \n", + "88 0 \n", + "89 0 \n", + "90 0 \n", + "91 42565 \n", + "\n", + "[92 rows x 11 columns]" + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Casa Bimbo '" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "id": "7e2e0f52", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = df.iloc[4]" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "id": "62c2a66b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Bolzano\n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale NaN\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 NaN\n", + "Ore totali rendicontate per il 2021 NaN\n", + "Name: 4, dtype: object" + ] + }, + "execution_count": 129, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "id": "05d1e376", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = gemeinde[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 131, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "id": "e4eca77c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Bolzano'" + ] + }, + "execution_count": 132, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + "cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + "df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + "df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]\n", + "ddff = pd.DataFrame()" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "id": "eee9a6ec", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 138, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "id": "ed99ae10", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "id": "f76d010f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 2020-10-19\n", + "9 2020-06-08\n", + "10 2019-09-02\n", + "11 2021-02-19\n", + "12 2019-08-19\n", + "13 2020-06-08\n", + "14 2021-09-13\n", + "15 2020-06-29\n", + "16 2021-09-06\n", + "17 2021-02-25\n", + "18 2020-08-17\n", + "19 2021-03-02\n", + "20 2020-08-25\n", + "21 2020-09-28\n", + "22 2021-02-24\n", + "23 2020-08-17\n", + "24 2019-09-23\n", + "25 2020-09-28\n", + "26 2020-01-29\n", + "27 2021-09-20\n", + "28 2020-08-26\n", + "29 2021-10-04\n", + "30 2019-02-18\n", + "31 2020-09-28\n", + "32 2021-02-04\n", + "33 2021-12-06\n", + "34 2021-01-04\n", + "35 2021-11-22\n", + "36 2019-09-02\n", + "37 2020-08-31\n", + "38 2020-08-31\n", + "39 2020-09-07\n", + "40 2020-08-03\n", + "41 2021-03-01\n", + "42 2020-01-13\n", + "43 2021-08-30\n", + "44 2020-08-24\n", + "45 2021-09-06\n", + "46 2021-02-10\n", + "47 2020-10-13\n", + "48 2019-09-02\n", + "49 2021-10-18\n", + "50 2021-10-11\n", + "51 2021-08-30\n", + "52 2021-05-25\n", + "53 2020-06-01\n", + "54 2021-11-08\n", + "55 2020-08-31\n", + "56 2020-10-05\n", + "57 2020-03-02\n", + "58 2019-09-23\n", + "59 2021-10-18\n", + "60 2020-12-28\n", + "61 2021-06-28\n", + "62 2021-09-20\n", + "63 2020-07-13\n", + "64 2021-08-30\n", + "65 2020-08-31\n", + "Name: Data inizio contratto (o data inizio assistenza se diversa), dtype: datetime64[ns]" + ] + }, + "execution_count": 140, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "id": "600803c2", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
81.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 " + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "condizione1 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] >= pd.to_datetime(\"19.10.2020\", format=\"%d.%m.%Y\")\n", + "condizione2 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] < pd.to_datetime(\"22.10.2020\", format=\"%d.%m.%Y\")\n", + "df[condizione1 & condizione2]" + ] + }, + { + "cell_type": "code", + "execution_count": 171, + "id": "5ccb9a95", + "metadata": {}, + "outputs": [], + "source": [ + "ddff = pd.DataFrame()\n", + "for ind in df.index:\n", + " if df[\"Comune di residenza assistente domiciliare all'infanzia\"][ind].lower() in (\"bolza\"):\n", + " if df[\"Data inizio contratto (o data inizio assistenza se diversa)\"][ind] > pd.to_datetime(\"17.10.2020\", format=\"%d.%m.%Y\") and df[\"Data inizio contratto (o data inizio assistenza se diversa)\"][ind] < pd.to_datetime(\"30.12.2020\", format=\"%d.%m.%Y\"):\n", + " print(\"bingo\")\n", + " if not ddff.empty:\n", + " print(ind)\n", + " ddff = pd.concat([ddff, df.loc[[ind]]])\n", + " else:\n", + " print(\"empty\")\n", + " print(ind)\n", + " ddff = df.loc[[ind]]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "da922451", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "id": "d158111c", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "df = df.reindex()" + ] + }, + { + "cell_type": "code", + "execution_count": 314, + "id": "390496be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
11
Numero \\nprogressivo3.0
Cognome e nome bambinoKajana Mia
Data di nascita2018-08-03 00:00:00
Codice fiscaleKJNMIA18M43A952A
Assistente domiciliare all'infanziaAmbach Maria
Comune di residenza assistente domiciliare all'infanziaEppan
Data inizio contratto (o data inizio assistenza se diversa)2019-08-06 00:00:00
Data fine contratto\\n(o data fine assistenza se diversa) *2020-05-04 00:00:00
Ore di assistenza \\n ai sensi della delibera\\nn. 666/201999.5
Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020144.75
Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020NaN
Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)66.25
Ore totali rendicontate per il 2020310.5
\n", + "
" + ], + "text/plain": [ + " 11\n", + "Numero \\nprogressivo 3.0\n", + "Cognome e nome bambino Kajana Mia\n", + "Data di nascita 2018-08-03 00:00:00\n", + "Codice fiscale KJNMIA18M43A952A\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2019-08-06 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-05-04 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 99.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... 144.75\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 66.25\n", + "Ore totali rendicontate per il 2020 310.5" + ] + }, + "execution_count": 314, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ddff.T" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "id": "265efbee", + "metadata": {}, + "outputs": [], + "source": [ + "c = df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains('bozen|eppan')" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "90008ae8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020',\n", + " 'Ore totali rendicontate per il 2021'],\n", + " dtype='object')" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "80ffa47b", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'DataFrame' object has no attribute 'colums'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [35]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolums\u001b[49m()\n", + "File \u001b[0;32m~/.local/lib/python3.9/site-packages/pandas/core/generic.py:5575\u001b[0m, in \u001b[0;36mNDFrame.__getattr__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 5568\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[1;32m 5569\u001b[0m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_internal_names_set\n\u001b[1;32m 5570\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_metadata\n\u001b[1;32m 5571\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_accessors\n\u001b[1;32m 5572\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_info_axis\u001b[38;5;241m.\u001b[39m_can_hold_identifiers_and_holds_name(name)\n\u001b[1;32m 5573\u001b[0m ):\n\u001b[1;32m 5574\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m[name]\n\u001b[0;32m-> 5575\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mobject\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getattribute__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'DataFrame' object has no attribute 'colums'" + ] + } + ], + "source": [ + "df.colums()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2020" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "af6a6cf6", + "metadata": {}, + "outputs": [], + "source": [ + " condizioneerrore = ((1920 * (df[\"GiorniAssistenzaAnnoRiferimento\"])) / 366) < df[\n", + " \"Ore totali rendicontate per il 2020\"\n", + " ]\n", + " \n", + " condizioneerrore2 = ((1920 * (df.groupby(\"Codice fiscale\")[\"GiorniAssistenzaAnnoRiferimento\"].transform(\"sum\")) / 366)) < df.groupby(\"Codice fiscale\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\")" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "08e4a7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "VNCDLN19B19A952G\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n" + ] + } + ], + "source": [ + "for i in df[condizioneerrore][\"Codice fiscale\"]:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "29ed03dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-313661308.7589.500-340.001058.252020-01-012020-12-31
9Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-102020-05-05570.0090.0000.0090.002020-03-102020-05-05
10Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-182020-12-31228559.5024.000-1.75581.752020-05-182020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-0412599.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.0071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-27326.500.0000.0026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-06126189.75270.500332.50792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-31165804.0010.2500.00814.252020-07-202020-12-31
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-23127231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-06127173.50279.500364.50817.502020-01-012020-05-06
18Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-062020-12-31179390.7520.0000.00410.752020-07-062020-12-31
19Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-032020-05-069455.00120.00050.00225.002020-02-032020-05-06
20Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-072020-02-0824.500.0000.004.502020-02-072020-02-08
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-0418.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-2117.000.0000.007.002020-08-212020-08-21
23Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-022020-03-04315.000.0000.0015.002020-03-022020-03-04
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-183274.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "18 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "19 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "20 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "23 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "9 Tramin 2018-05-29 FREJRU18E29A952R \n", + "10 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "18 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "19 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "20 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "23 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "9 2020-03-10 \n", + "10 2020-05-18 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "18 2020-07-06 \n", + "19 2020-02-03 \n", + "20 2020-02-07 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-02 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "9 2020-05-05 \n", + "10 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "18 2020-12-31 \n", + "19 2020-05-06 \n", + "20 2020-02-08 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-04 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 366 \n", + "9 57 \n", + "10 228 \n", + "11 125 \n", + "12 12 \n", + "13 3 \n", + "14 126 \n", + "15 165 \n", + "16 127 \n", + "17 127 \n", + "18 179 \n", + "19 94 \n", + "20 2 \n", + "21 1 \n", + "22 1 \n", + "23 3 \n", + "24 32 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "9 0.00 \n", + "10 559.50 \n", + "11 99.50 \n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "16 231.50 \n", + "17 173.50 \n", + "18 390.75 \n", + "19 55.00 \n", + "20 4.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "23 15.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "9 90.00 \n", + "10 24.00 \n", + "11 144.75 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.50 \n", + "18 20.00 \n", + "19 120.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "9 0.00 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 332.50 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "18 0.00 \n", + "19 50.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "9 90.00 2020-03-10 2020-05-05 \n", + "10 581.75 2020-05-18 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "18 410.75 2020-07-06 2020-12-31 \n", + "19 225.00 2020-02-03 2020-05-06 \n", + "20 4.50 2020-02-07 2020-02-08 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "23 15.00 2020-03-02 2020-03-04 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9f22c6d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/.vscode/settings.json b/pages/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..de288e1eab6a537caed290ce0fc5e70be7ae9dba --- /dev/null +++ b/pages/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.formatting.provider": "black" +} \ No newline at end of file diff --git "a/pages/01_TagesMu\314\210tter.py.previous" "b/pages/01_TagesMu\314\210tter.py.previous" new file mode 100644 index 0000000000000000000000000000000000000000..298290c72a056b507013d9aa339ad3837e6555d0 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter.py.previous" @@ -0,0 +1,3214 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + COSTANTI2020 = { + "DATAINIZIOMINIMA": pd.to_datetime("18.05.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MIN": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "DATAFINEMASSIMA": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "ORE2020": 1920, + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "EINGEWÖHNUNG_DATAINIZIO_MIN": pd.to_datetime("13.02.2020", format="%d.%m.%Y"), + "EINGEWÖHNUNG_DATAINIZIO_MAX": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "KONTROLLECOVID_DATAINIZIOASSISTENZA": pd.to_datetime( + "05.03.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID_DATAFINEASSISTENZA2": pd.to_datetime( + "30.10.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID2_DATAINIZIOASSISTENZA": pd.to_datetime( + "24.11.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN": pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX": pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" + ), + } + COSTANTI2021 = { + "COVID4_DATAINIZIO_MIN": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("28.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MIN": pd.to_datetime("08.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MAX": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + } + + + COSTANTI2022 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2020", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2020": COSTANTI2020, "2021": COSTANTI2021, "2022": COSTANTI2022} + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + # "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Errore dati 543", + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreFinanziamentoCompensativo": "Finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Finanziamento compensativo #2", + "errErroreCovid": "Covid #1", + "errErroreCovid2": "Covid #2", + "errErroreCovid3": "Covid #3", + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung": "Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Ambientamento servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errMassimo543": "Valore massimo ore 543", + "errSommaOre": "Tabella ore per ente gestore", + "errMassimoFC": "Valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + ERRORDICT2021 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + } + + ERRORDICT2022 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + "errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2020": ERRORDICT2020, "2021": ERRORDICT2021, "2022": ERRORDICT2022} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 2.4.5-2022)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", ("2020", "2021", "2022", "2023"), index=2 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden): + self.checks = interface.checks + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if flag != "casospeciale": + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome e nome bambino"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + #self.dwnld( + # self.df.sort_values(by=["Cognome e nome bambino"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + #) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file(self.dffinal.sort_values(by=["Cognome e nome bambino"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + #self.dwnld( + # self.dffinal.sort_values(by=["Cognome e nome bambino"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + #) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome e nome bambino"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome e nome bambino"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] + + self.df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"] + ) != self.df[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + self.df = self.df.reset_index(drop=True) + if self.ANNO_RIFERIMENTO == "2020": + df1 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + df1025 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + ] + ) + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + ] + ) + # iteriamo tutti i record del df controllando che 1025 non sia zero + # e controlliamo che codfisc occorra solo una volta + + #>>> non possiamo usare questa soluzione se il nome della colonna contiene il carattere "nuova riga" + #>>> filtered_df = self.df.eval("`Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020` > 0") + #>>> df1025 = filtered_df.drop_duplicates(subset=["Codice fiscale", "Comune"]) + + for ind in self.df.index: + if ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if df1025.empty: + df1025 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df1025["Codice fiscale"]) + & (self.df["Comune"][ind] == df1025["Comune"]) + ).any(): + df1025 = pd.concat([df1025, self.df.loc[[ind]]]) + else: + continue + + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Comune"][ind] == df666["Comune"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + df1 = self.df.groupby("Comune", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + df3 = df1025.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + df3bis = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore totali rendicontate per il "+ self.ANNO_RIFERIMENTO + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + # rinominiamo 'comune' in 'gemeinde' per facilitare l'outer join che segue + dfx.columns = [ + "Gemeinde", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Conteggio Nr. bimbi ore 666", + "Somma Ore Assistenza 666", + "Conteggio Nr. bimbi ore 1025", + + "Somma Ore Assistenza 1025", + "Ore totali rendicontate per il 2021", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Gemeinde',ascending=True) + dfx = pd.merge(dfx,df_gemeinden,on='Gemeinde', how='outer') + + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + + + + riga_vuota = {"Comune": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Comune": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "05.09." + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + self.df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") + == True + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto\n(o data fine assistenza se diversa) *", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome e nome bambino"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + + def load_gemeinden(self): + df_gemeinden = pd.read_csv('../commontools/Gemeinden.csv') + df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + return df_gemeinden + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO == "2020": + df = pd.read_excel(uploaded_file, usecols="A:M") + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:L") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:L") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + + self.dataframes.append(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + traeger = df.iloc[2] + + if self.ANNO_RIFERIMENTO == "2020": + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4].title() + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3].title() + # st.write(gemeinde) + # st.write(traeger) + + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + df.columns = [ + "Numero \nprogressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + # "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO, + ] + + # uniamo cognome e nome + df.insert(1, "Cognome e nome bambino", df["Cognome"] + " " + df["Nome"]) + df.drop(["Cognome", "Nome"], axis=1, inplace=True) + traeger = traeger[0].title() + gemeinde = df.iloc[4] + gemeinde = gemeinde[ + 0 + ] # .title() - togliamo title() perche' produce troppip warning + # st.write(gemeinde) + # st.write(traeger) + + gemeindeInserito = gemeinde + + # df["Ore totali rendicontate per il 2021"] = df["Ore totali rendicontate per il 2021"].astype("float") + + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.error( + f"Errore durante caricamento file dei comuni'GemeindenComuni.xlsx'; erore: {e}" + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + if ( + gemeindeInserito not in dfGemeinden["Gemeinde"].unique() + and gemeindeInserito not in dfGemeinden["Comune"].unique() + ): + st.warning( + f"L'ente '{traeger}' ha inserito un nome comune non ufficiale: '{gemeindeInserito}'. \n\r Il file verra' usato comunque con il comune inserito. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + del dfGemeinden + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero \nprogressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero \nprogressivo", "Cognome e nome bambino"] + ] + .groupby("Numero \nprogressivo", as_index=False) + .first() + ) + df_no_index["Numero \nprogressivo"] = df_no_index[ + "Numero \nprogressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = ( + ~df["Numero \nprogressivo"].isna() & df["Cognome e nome bambino"].isna() + ) + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(self.ANNO_RIFERIMENTO) + + #try: + # df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + # "Data fine contratto\n(o data fine assistenza se diversa) *" + # ].astype("datetime64[ns]") + #except Exception as e: + # st.error(f"Errore conversione data fine contratto") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data di nascita contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + if df["Data di nascita"].isna().any(): + st.error(f"{file.name} --> mancano valori per la data di nascita.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT) + processor.process_data() + df_gemeinden = processor.load_gemeinden() + errori = trovaErrori(processor.get_data(), interface, df_gemeinden) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) diff --git "a/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py" "b/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py" new file mode 100644 index 0000000000000000000000000000000000000000..0e60aee26ac651a6ad44618458a7d446aa795518 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py" @@ -0,0 +1,2026 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import os +import sys + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +# Get the absolute path to the script's directory +current_dir = os.path.dirname(os.path.abspath(__file__)) +# Get the parent directory +parent_dir = os.path.dirname(current_dir) +# Add parent directory to sys.path +sys.path.append(parent_dir) + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# CONTROLLO ERRORI TAGESMUETTER") +st.markdown('## Roberta Bovo Special Edition 🤗 (ver. 4.1.0)') + +# Add vertical spacing to create better separation from file uploader +st.markdown("
", unsafe_allow_html=True) + +# st.write(f"{ReportGenerator.get_version(1)}, {helpers.get_version(1)}, {makeInterface.get_version(1)}") + +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023","2024","2025"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + self.ComuneTedesco = interface.COMUNETEDESCO + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023","2024","2025","2026"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.markdown("
", unsafe_allow_html=True) + c2.markdown("
", unsafe_allow_html=True) + + c1.info(f"**Sto elaborando {file.name}...**") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023","2024", "2025"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + #st.write(f"codice_ente {df.iloc[2, 12]}") + codice_comune = df.iloc[4, 12] + #st.write(f"codice_comune {df.iloc[4, 12]}") + anno = df.iloc[0, 5] + + #st.write("pippo" + self.ComuneTedesco) + try: + #st.write("pippo" + self.ComuneTedesco) + if self.ComuneTedesco: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Gemeinde" + ].values[0] + else: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + + # Check if numbers in "Numero progressivo" are not continuous, i.e. a number is missing, like the "3" in "1, 2, 4, 5, etc." + # Only apply to rows with valid numeric values in "Numero progressivo" + valid_rows = df["Numero progressivo"].notna() + missing_nums = np.array([]) # Initialize missing_nums here to avoid UnboundLocalError + + if valid_rows.any(): + # Get unique valid numeric values and sort them + unique_nums = df.loc[valid_rows, "Numero progressivo"].unique() + unique_nums = np.sort(unique_nums) + + # Check if the sequence is continuous + if len(unique_nums) >= 2: # Need at least 2 numbers to check continuity + expected_sequence = np.arange(unique_nums[0], unique_nums[-1] + 1) + missing_nums = np.setdiff1d(expected_sequence, unique_nums) + + if len(missing_nums) > 0: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi non continui nel file {file.name}. " + f"Mancano i numeri: {', '.join(map(str, missing_nums))}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + f"Trovati numeri progressivi non continui. Mancano: {', '.join(map(str, missing_nums.astype(int)))}" + ) + + with st.expander(f"Numeri progressivi non continui nel file {file.name}"): + st.write( + f"Attenzione: nella sequenza dei numeri progressivi mancano i seguenti numeri: {', '.join(map(str, missing_nums.astype(int)))}" + ) + # Display the sequence found in the file + st.write("Sequenza trovata nel file:") + st.write(unique_nums) + + + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi duplicati nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + + with st.expander( + f"Record con numeri progressivi duplicati: {len(df_no_index)} occorrenze" + ): + st.write( + "Attenzione: i seguenti record hanno numeri progressivi duplicati e potrebbero richiedere attenzione." + ) + st.write(df_no_index) + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + + # Check for duplicate children with same Tagesmütter and same start date + same_child_same_tagesmutter_same_startdate = ( + df.duplicated( + subset=[ + "Cognome", + "Nome", + "CognomeAssDom", + "NomeAssDom", + "Data inizio contratto (o data inizio assistenza se diversa)", + ], + keep=False, + ) + ) + + if same_child_same_tagesmutter_same_startdate.any(): + count_duplicates = same_child_same_tagesmutter_same_startdate.sum() + #c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito lo stesso bambino con la stessa Tagesmutter e stessa data di inizio {count_duplicates} volte" + ) + + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + f"Trovati {count_duplicates} record duplicati con lo stesso bambino, stessa Tagesmutter e stessa data di inizio" + ) + + # Display the duplicate records for debugging +# if interface.DEBUGGENERAL + with st.expander( + f"Record duplicati (stesso bambino, stessa Tagesmutter e stessa data di inizio): {count_duplicates} occorrenze" + ): + st.write( + "Attenzione: i seguenti record sono duplicati e potrebbero richiedere attenzione." + ) + dups = df[same_child_same_tagesmutter_same_startdate].sort_values( + by=[ + "Cognome", + "Nome", + "CognomeAssDom", + "NomeAssDom", + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ) + st.write(dups) + + flag = 1 + + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + + # Get the directory where the script is located + # script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Build the full path to the Excel file + # file_path = os.path.join(script_dir, "GemeindenMitKodex.xlsx") + #st.write(file_path) + + # Read the file + try: + df_gemeinden = pd.read_excel("pages/GemeindenMitKodex.xlsx", dtype=dtype_spec) + #st.write(f"Columns 1: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + _df_gemeinden_backup = df_gemeinden.copy() + except Exception as e: + st.error(f"Primo; errore: {e}") + + try: + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + #st.write(f"Columns 2: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + if not isinstance(df_gemeinden, pd.DataFrame): + st.error("ATTENZIONE: df_gemeinden è stato sovrascritto — non è più un DataFrame!") + df_gemeinden = _df_gemeinden_backup.copy() + st.warning("df_gemeinden è stato ripristinato dalla copia di backup.") + except Exception as e: + st.write(df_gemeinden) + st.error(f"Secondo; errore: {e}") + #df_gemeinden = pd.read_excel( + # "GemeindenMitKodex.xlsx", dtype=dtype_spec + #) + #df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + #st.write(file_path) + #st.write(f"dtype_spec: {dtype_spec} ({type(dtype_spec)})") + + st.error(f"Errore durante caricamento file dei comuni; Errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + # Build the full path to the Excel file + file_path = os.path.join(script_dir, "TM_TraegerMitKodex.xlsx") + df_traeger = pd.read_excel(file_path, dtype=dtype_spec) + + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py.x" "b/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..fadb76f7c6c45aeb6425c507f7f6837b75fd1dce --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_RobertaBovoEdition.py.x" @@ -0,0 +1,1864 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# CONTROLLO ERRORI TAGESMUETTER") +st.markdown('## Roberta Bovo Special Edition 🤗 (ver. 4.0.3)') +st.write(f"{ReportGenerator.get_version(1)}, {helpers.get_version(1)}, {makeInterface.get_version(1)}") + +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0, 5] + + try: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel( + "pages/GemeindenMitKodex.xlsx", dtype=dtype_spec + ) + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel("../commontools/TM_TraegerMitKodex.xlsx") + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.2.py.outOfService" "b/pages/01_TagesMu\314\210tter_ver.2.py.outOfService" new file mode 100644 index 0000000000000000000000000000000000000000..848c91faf2c749faadff0fee723a52164fd62acd --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.2.py.outOfService" @@ -0,0 +1,3229 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + COSTANTI2020 = { + "DATAINIZIOMINIMA": pd.to_datetime("18.05.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MIN": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "DATAFINEMASSIMA": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "ORE2020": 1920, + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "EINGEWÖHNUNG_DATAINIZIO_MIN": pd.to_datetime("13.02.2020", format="%d.%m.%Y"), + "EINGEWÖHNUNG_DATAINIZIO_MAX": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "KONTROLLECOVID_DATAINIZIOASSISTENZA": pd.to_datetime( + "05.03.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID_DATAFINEASSISTENZA2": pd.to_datetime( + "30.10.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID2_DATAINIZIOASSISTENZA": pd.to_datetime( + "24.11.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN": pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX": pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" + ), + } + COSTANTI2021 = { + "COVID4_DATAINIZIO_MIN": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("28.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MIN": pd.to_datetime("08.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MAX": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + } + + + COSTANTI2022 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2020", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2020": COSTANTI2020, "2021": COSTANTI2021, "2022": COSTANTI2022} + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + # "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Errore dati 543", + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreFinanziamentoCompensativo": "Finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Finanziamento compensativo #2", + "errErroreCovid": "Covid #1", + "errErroreCovid2": "Covid #2", + "errErroreCovid3": "Covid #3", + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung": "Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Ambientamento servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errMassimo543": "Valore massimo ore 543", + "errSommaOre": "Tabella ore per ente gestore", + "errMassimoFC": "Valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + ERRORDICT2021 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + } + + ERRORDICT2022 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + "errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2020": ERRORDICT2020, "2021": ERRORDICT2021, "2022": ERRORDICT2022} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 2.4.6-2022)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", ("2020", "2021", "2022", "2023"), index=2 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden): + self.checks = interface.checks + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if flag != "casospeciale": + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome e nome bambino"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + #self.dwnld( + # self.df.sort_values(by=["Cognome e nome bambino"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + #) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file(self.dffinal.sort_values(by=["Cognome e nome bambino"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + #self.dwnld( + # self.dffinal.sort_values(by=["Cognome e nome bambino"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + #) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome e nome bambino"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome e nome bambino"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] + + self.df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"] + ) != self.df[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + self.df = self.df.reset_index(drop=True) + if self.ANNO_RIFERIMENTO == "2020": + df1 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + df1025 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + ] + ) + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + ] + ) + # iteriamo tutti i record del df controllando che 1025 non sia zero + # e controlliamo che codfisc occorra solo una volta + + #>>> non possiamo usare questa soluzione se il nome della colonna contiene il carattere "nuova riga" + #>>> filtered_df = self.df.eval("`Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020` > 0") + #>>> df1025 = filtered_df.drop_duplicates(subset=["Codice fiscale", "Comune"]) + + for ind in self.df.index: + if ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if df1025.empty: + df1025 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df1025["Codice fiscale"]) + & (self.df["Comune"][ind] == df1025["Comune"]) + ).any(): + df1025 = pd.concat([df1025, self.df.loc[[ind]]]) + else: + continue + + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Comune"][ind] == df666["Comune"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + df1 = self.df.groupby("Comune", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + df3 = df1025.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + df3bis = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore totali rendicontate per il "+ self.ANNO_RIFERIMENTO + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + # rinominiamo 'comune' in 'gemeinde' per facilitare l'outer join che segue + dfx.columns = [ + "Gemeinde", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Conteggio Nr. bimbi ore 666", + "Somma Ore Assistenza 666", + "Conteggio Nr. bimbi ore 1025", + + "Somma Ore Assistenza 1025", + "Ore totali rendicontate per il 2021", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Gemeinde',ascending=True) + dfx = pd.merge(dfx,df_gemeinden,on='Gemeinde', how='outer') + + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + + + + riga_vuota = {"Comune": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Comune": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "05.09." + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + self.df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") + == True + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto\n(o data fine assistenza se diversa) *", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome e nome bambino"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + + def load_gemeinden(self): + df_gemeinden = pd.read_csv('../commontools/Gemeinden.csv') + df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + return df_gemeinden + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO == "2020": + df = pd.read_excel(uploaded_file, usecols="A:M") + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:L") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:L") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + + self.dataframes.append(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + traeger = df.iloc[2] + + if self.ANNO_RIFERIMENTO == "2020": + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4].title() + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3].title() + # st.write(gemeinde) + # st.write(traeger) + + elif self.ANNO_RIFERIMENTO in ["2021","2022"]: + df.columns = [ + "Numero \nprogressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + # "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO, + ] + + # uniamo cognome e nome + df.insert(1, "Cognome e nome bambino", df["Cognome"] + " " + df["Nome"]) + df.drop(["Cognome", "Nome"], axis=1, inplace=True) + traeger = traeger[0].title() + gemeinde = df.iloc[4] + gemeinde = gemeinde[ + 0 + ] # .title() - togliamo title() perche' produce troppip warning + # st.write(gemeinde) + # st.write(traeger) + + gemeindeInserito = gemeinde + + + + # df["Ore totali rendicontate per il 2021"] = df["Ore totali rendicontate per il 2021"].astype("float") + + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.error( + f"Errore durante caricamento file dei comuni'GemeindenComuni.xlsx'; erore: {e}" + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + if ( + gemeindeInserito not in dfGemeinden["Gemeinde"].unique() + and gemeindeInserito not in dfGemeinden["Comune"].unique() + ): + st.warning( + f"L'ente '{traeger}' ha inserito un nome comune non ufficiale: '{gemeindeInserito}'. \n\r Il file verra' usato comunque con il comune inserito. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + del dfGemeinden + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + + if df[f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}"].isnull().sum(): + somma = df[f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero \nprogressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero \nprogressivo", "Cognome e nome bambino"] + ] + .groupby("Numero \nprogressivo", as_index=False) + .first() + ) + df_no_index["Numero \nprogressivo"] = df_no_index[ + "Numero \nprogressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = ( + ~df["Numero \nprogressivo"].isna() & df["Cognome e nome bambino"].isna() + ) + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(self.ANNO_RIFERIMENTO) + + #try: + # df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + # "Data fine contratto\n(o data fine assistenza se diversa) *" + # ].astype("datetime64[ns]") + #except Exception as e: + # st.error(f"Errore conversione data fine contratto") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data di nascita contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + if df["Data di nascita"].isna().any(): + st.error(f"{file.name} --> mancano valori per la data di nascita.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT) + processor.process_data() + df_gemeinden = processor.load_gemeinden() + errori = trovaErrori(processor.get_data(), interface, df_gemeinden) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) diff --git "a/pages/01_TagesMu\314\210tter_ver.3.05_2023.py.previous" "b/pages/01_TagesMu\314\210tter_ver.3.05_2023.py.previous" new file mode 100644 index 0000000000000000000000000000000000000000..268c40f0b6047ed869e6bbd863af789ddc586d11 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.05_2023.py.previous" @@ -0,0 +1,3133 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.05-2023)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if flag != "casospeciale": + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + #self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + #) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file(self.dffinal.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + #self.dwnld( + # self.dffinal.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + #) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + self.df = self.df.reset_index(drop=True) + + #st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + #st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + + #st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + #st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + #st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + #df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + #df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + #dfx = pd.merge(dfx, df3, on="Comune", how="outer") + #dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + #st.write(dfx) + + #st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + #st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + #st.write(dfx) + #st.write(df_allegato666) + + # ci serve per deidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + #st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + #st.write('here comes dfxx') + #st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + #columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "05.09." + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = "12-31-" + str(self.ANNO_RIFERIMENTO) + + #try: + # df["Data fine contratto (o data fine assistenza se diversa)"] = df[ + # "Data fine contratto (o data fine assistenza se diversa)" + # ].astype("datetime64[ns]") + #except Exception as e: + # st.error(f"Errore conversione data fine contratto") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data di nascita contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + if df["Data di nascita"].isna().any(): + st.error(f"{file.name} --> mancano valori per la data di nascita.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + try: + df["Data fine contratto (o data fine assistenza se diversa)"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.warning("L'allegato 666 non e' stato caricato e non verra' di conseguenza usato") + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il cricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.06_2023.py.previous" "b/pages/01_TagesMu\314\210tter_ver.3.06_2023.py.previous" new file mode 100644 index 0000000000000000000000000000000000000000..fa61eed1e627e007ddf9b7f504bd9b2b9908f071 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.06_2023.py.previous" @@ -0,0 +1,3164 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.06-2023)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if flag != "casospeciale": + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + #self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + #) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file(self.dffinal.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + #self.dwnld( + # self.dffinal.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + #) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + self.df = self.df.reset_index(drop=True) + + #st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + #st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + + #st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + #st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + #st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + #df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + #df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + #dfx = pd.merge(dfx, df3, on="Comune", how="outer") + #dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + #st.write(dfx) + + #st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + #st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + #st.write(dfx) + #st.write(df_allegato666) + + # ci serve per deidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + #st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + #st.write('here comes dfxx') + #st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + #columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "04.09." #modificato 24/6/2024 su richeista RobertaB + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + st.info(f"Sto elaborando {file.name}...") + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = "12-31-" + str(self.ANNO_RIFERIMENTO) + + try: + # df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + #st.write(df) + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + return df + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str): + year_part = str(date_str).split('-')[-3] + #st.write(year_part) # Get the year part, which is after the last '.' + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df, date_column,file): + #st.write(date_column) + #st.write(df) + #df[date_column]= pd.to_datetime(df[date_column]).dt.strftime('%d-%m-%Y') + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + #st.write(df) + + #mask = df[date_column].apply(self.is_incorrect_year) + #incorrect_dates_df = df[mask] + #st.write("\nAnno invalido") + #st.write(incorrect_dates_df) + #invalid_dates_df_2 = df["Parsed Date"].where(df["Parsed Date"].dt.year.between(*valid_year_range), pd.NaT) + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty:# or not invalid_dates_df_2.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + #st.write(df) + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.warning("L'allegato 666 non e' stato caricato e non verra' di conseguenza usato") + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il cricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.12_2024.py.last" "b/pages/01_TagesMu\314\210tter_ver.3.12_2024.py.last" new file mode 100644 index 0000000000000000000000000000000000000000..4bd8695d0940b99e081b9dc3e564cbdb5228f005 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.12_2024.py.last" @@ -0,0 +1,3179 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.12-2024)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + + # Check if 'Colonna_L_da_cancellare_dopo' exists and delete it + if 'Colonna_L_da_cancellare_dopo' in dftosave.columns: + del dftosave['Colonna_L_da_cancellare_dopo'] + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if not interface.MOSTRACOLONNEERRORE: + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + #self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + #) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file(self.dffinal.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + #self.dwnld( + # self.dffinal.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + #) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + #if df_allegato666 == None: + # st.warning("Conteggio bimbi per comune e tipologia ore non eseguito perche' manca allegato666") + # return + + self.df = self.df.reset_index(drop=True) + + #st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + #st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + + #st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + #st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + #st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + #df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + #df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + #].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + #dfx = pd.merge(dfx, df3, on="Comune", how="outer") + #dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + #st.write(dfx) + + #st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + #st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + #st.write(dfx) + #st.write(df_allegato666) + + # ci serve per decidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + #st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + #st.write('here comes dfxx') + #st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + #columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "04.09." #modificato 24/6/2024 su richeista RobertaB + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + st.info(f"Sto elaborando {file.name}...") + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + # df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + #st.write(df) + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + return df + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str): + year_part = str(date_str).split('-')[-3] + #st.write(year_part) # Get the year part, which is after the last '.' + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df, date_column,file): + #st.write(date_column) + #st.write(df) + #df[date_column]= pd.to_datetime(df[date_column]).dt.strftime('%d-%m-%Y') + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + #st.write(df) + + #mask = df[date_column].apply(self.is_incorrect_year) + #incorrect_dates_df = df[mask] + #st.write("\nAnno invalido") + #st.write(incorrect_dates_df) + #invalid_dates_df_2 = df["Parsed Date"].where(df["Parsed Date"].dt.year.between(*valid_year_range), pd.NaT) + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty:# or not invalid_dates_df_2.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + #st.write(df) + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.13_2023.py.mancaFragment" "b/pages/01_TagesMu\314\210tter_ver.3.13_2023.py.mancaFragment" new file mode 100644 index 0000000000000000000000000000000000000000..e9afb09f7824970d7b87884785f965fa19e8108e --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.13_2023.py.mancaFragment" @@ -0,0 +1,3206 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.12-2024)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + # pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file(self, dftosave, nome_file, flag=None): # questa la versione in uso + + # Check if 'Colonna_L_da_cancellare_dopo' exists and delete it + if 'Colonna_L_da_cancellare_dopo' in dftosave.columns: + del dftosave['Colonna_L_da_cancellare_dopo'] + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + # if not interface.MOSTRACOLONNEERRORE: + # dftosave = self.drop_columns(dftosave) + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + # def prepare_for_excel( + # self, df + # ) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", 'mantieniColonneErrore' + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + # self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + # ) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + # if df_allegato666 == None: + # st.warning("Conteggio bimbi per comune e tipologia ore non eseguito perche' manca allegato666") + # return + + self.df = self.df.reset_index(drop=True) + + # st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + # st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + # st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + # df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + # dfx = pd.merge(dfx, df3, on="Comune", how="outer") + # dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + # st.write(dfx) + + # st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + # st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + # st.write(dfx) + # st.write(df_allegato666) + + # ci serve per decidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + # st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + # st.write('here comes dfxx') + # st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + # columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "04.09." #modificato 24/6/2024 su richeista RobertaB + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum(self): + + # prima vediamo se ci sono bambini in comuni diversi ma con periodi + # che si sovvrappongoni o che sono uguali + # Find codici fiscali present in multiple cities + multi_city_codes = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Self-merge to find overlapping periods in different cities + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define overlap condition + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply condition + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique codes + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[["Cognome", "Nome","Comune","Data inizio contratto (o data inizio assistenza se diversa)","Data fine contratto (o data fine assistenza se diversa)","filename"]].reset_index(drop=True) + result_df = result_df.sort_values(by=["Cognome","Nome"]) + + # st.warning(result_codes) + + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + + # try: + # # non facciamo altro che salvare il file in caso di problemi + # self.df.to_excel("gesamtstd.xlsx") + # except Exception as e: + # st.error(f"Error writing gesamtstf.xlsx; errore {e}") + # if interface.TOLLERANZAZERO: + # st.error("ELaborazione terminata") + # st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.warning("Attenzione: i seguenti bambini non sono stati considerati per il controllo poiche' hanno periodi uguali o sovvraposti per comuni divesi") + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + st.info(f"Sto elaborando {file.name}...") + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + # df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + #st.write(df) + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + return df + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str): + year_part = str(date_str).split('-')[-3] + #st.write(year_part) # Get the year part, which is after the last '.' + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df, date_column,file): + #st.write(date_column) + #st.write(df) + #df[date_column]= pd.to_datetime(df[date_column]).dt.strftime('%d-%m-%Y') + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + #st.write(df) + + #mask = df[date_column].apply(self.is_incorrect_year) + #incorrect_dates_df = df[mask] + #st.write("\nAnno invalido") + #st.write(incorrect_dates_df) + #invalid_dates_df_2 = df["Parsed Date"].where(df["Parsed Date"].dt.year.between(*valid_year_range), pd.NaT) + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty:# or not invalid_dates_df_2.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + #st.write(df) + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.13_2024.py.lastProduction" "b/pages/01_TagesMu\314\210tter_ver.3.13_2024.py.lastProduction" new file mode 100644 index 0000000000000000000000000000000000000000..dadade540971458c42868104687951b20ae6e963 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.13_2024.py.lastProduction" @@ -0,0 +1,3211 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.12-2024)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + # pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file(self, dftosave, nome_file, flag=None): # questa la versione in uso + + # Check if 'Colonna_L_da_cancellare_dopo' exists and delete it + if 'Colonna_L_da_cancellare_dopo' in dftosave.columns: + del dftosave['Colonna_L_da_cancellare_dopo'] + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + # if not interface.MOSTRACOLONNEERRORE: + # dftosave = self.drop_columns(dftosave) + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + # def prepare_for_excel( + # self, df + # ) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", 'mantieniColonneErrore' + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + # self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + # ) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + # self.dwnld( + # self.dffinal.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON SOLO ERRORI", + # "soloerrori", + # ) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + # if df_allegato666 == None: + # st.warning("Conteggio bimbi per comune e tipologia ore non eseguito perche' manca allegato666") + # return + + self.df = self.df.reset_index(drop=True) + + # st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + # st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + # st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + # df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + # dfx = pd.merge(dfx, df3, on="Comune", how="outer") + # dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + # st.write(dfx) + + # st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + # st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + # st.write(dfx) + # st.write(df_allegato666) + + # ci serve per decidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + # st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + # st.write('here comes dfxx') + # st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + # columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "04.09." #modificato 24/6/2024 su richeista RobertaB + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum(self): + + # prima vediamo se ci sono bambini in comuni diversi ma con periodi + # che si sovvrappongoni o che sono uguali + # Find codici fiscali present in multiple cities + multi_city_codes = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Self-merge to find overlapping periods in different cities + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define overlap condition + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply condition + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique codes + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[["Cognome", "Nome","Comune","Data inizio contratto (o data inizio assistenza se diversa)","Data fine contratto (o data fine assistenza se diversa)","filename"]].reset_index(drop=True) + result_df = result_df.sort_values(by=["Cognome","Nome"]) + + # st.warning(result_codes) + + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + + # try: + # # non facciamo altro che salvare il file in caso di problemi + # self.df.to_excel("gesamtstd.xlsx") + # except Exception as e: + # st.error(f"Error writing gesamtstf.xlsx; errore {e}") + # if interface.TOLLERANZAZERO: + # st.error("ELaborazione terminata") + # st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.warning("Attenzione: i seguenti bambini non sono stati considerati per il controllo poiche' hanno periodi uguali o sovvraposti per comuni divesi") + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + st.info(f"Sto elaborando {file.name}...") + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + # df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + #st.write(df) + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + return df + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str): + year_part = str(date_str).split('-')[-3] + #st.write(year_part) # Get the year part, which is after the last '.' + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df, date_column,file): + #st.write(date_column) + #st.write(df) + #df[date_column]= pd.to_datetime(df[date_column]).dt.strftime('%d-%m-%Y') + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + #st.write(df) + + #mask = df[date_column].apply(self.is_incorrect_year) + #incorrect_dates_df = df[mask] + #st.write("\nAnno invalido") + #st.write(incorrect_dates_df) + #invalid_dates_df_2 = df["Parsed Date"].where(df["Parsed Date"].dt.year.between(*valid_year_range), pd.NaT) + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty:# or not invalid_dates_df_2.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + #st.write(df) + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.15_2023.py.x" "b/pages/01_TagesMu\314\210tter_ver.3.15_2023.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..e52f4e5186aa07d9de2dd627867f45044c4f8bfb --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.15_2023.py.x" @@ -0,0 +1,3207 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + #"errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia", # ok + #"errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + #"errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + # tolto per il 2023 su richiesta Roberta "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + #"errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + # tolto per il 2023 su richiesta Roberta "errOre1025": "Controllo ore 1025 dopo 31.03.2022", + # tolto per il 2023 su richiesta Roberta"errLista1025": "Tabella Tagesmütter con bimbi con ore 1025 durante quarantene (< 01.04.2022)" + } + + ERRORDICT = {"2023": ERRORDICT2023} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.12-2024)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_allegato666() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self): + self.uploaded_allegato666 = st.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + @st.fragment() + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + # pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + @st.fragment() + def download_excel_file(self, dftosave, nome_file, flag=None): # questa la versione in uso + + # Check if 'Colonna_L_da_cancellare_dopo' exists and delete it + if 'Colonna_L_da_cancellare_dopo' in dftosave.columns: + del dftosave['Colonna_L_da_cancellare_dopo'] + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + # if not interface.MOSTRACOLONNEERRORE: + # dftosave = self.drop_columns(dftosave) + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + # def prepare_for_excel( + # self, df + # ) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by=["Cognome","Nome"], ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file(self.df.sort_values(by=["Cognome","Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", 'mantieniColonneErrore' + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + # self.dwnld( + # self.df.sort_values(by=["Cognome","Nome"]), + # "SCARICARE TABELLA CON TUTTI I DATI", + # "tuttidati", + # ) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + self.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore", + ) + + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome","Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errLista1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] <= pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Tabella riassuntiva Tagesmuetter con bimbi con ore 1025 durante quarantene (< 01.04.2022)") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 prima del 01.04.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + # rimoviamo colonne come richiesto da RobertaB + dftemp = dftemp.drop(dftemp.columns[[4, 5, 7, 9, 13, 14, 15]], axis=1) + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista_ore1025_prima_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "lista1025", + ) + # settiamo il flag bool per la tabella finale + # self.df.loc[condizione_errore, "_ore1025_dopo_31032022"] = True + + def errOre1025(self): + condizione_0 = self.df["Data inizio contratto (o data inizio assistenza se diversa)"] > pd.to_datetime("31.03.2022", format="%d.%m.%Y") + condizione_1 = self.df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] > 0 + condizione_errore = condizione_0 & condizione_1 + if not self.df[condizione_errore].empty: + expndr = st.expander("Trovati errori per valori 1025 dopo il 31.03.2022") + with expndr: + st.info("Elenco dei bambini che hanno un valore per ore 1025 dopo il 31.03.2022") + dftemp = self.df[condizione_errore] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_ore1025_dopo_31032022.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "err1025", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_errore, "err_ore1025_dopo_31032022"] = True + + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate ai sensi della delibera n. 1025/2020" + ] + + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] + ) != self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + # if df_allegato666 == None: + # st.warning("Conteggio bimbi per comune e tipologia ore non eseguito perche' manca allegato666") + # return + + self.df = self.df.reset_index(drop=True) + + # st.write(self.df) + + if self.ANNO_RIFERIMENTO in ["2023"]: + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # st.write(self.df) + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + # st.write(df666) + + df1 = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # st.write(df1) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + # st.write(df2) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # df3 = df1025.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + # df3bis = self.df.groupby("Comune", as_index=False)[ + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + # ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Com_code", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + # dfx = pd.merge(dfx, df3, on="Comune", how="outer") + # dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + # st.write(dfx) + + # st.write(dfx) + # rinominiamo le colonne + dfx.columns = [ + "Com_code", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + + # "Nr. bimbi ore rendicontate", + ] + dfx = dfx.sort_values(by='Com_code',ascending=True) + # st.write(dfx) + dfx = pd.merge(dfx,df_gemeinden,on='Com_code', how='outer') + + # ora facciamo il merge con allegato666 + + # st.write(dfx) + # st.write(df_allegato666) + + # ci serve per decidere dopo come orfintr la lista: in base ai nomi cmiune ted o ital + lingua = df_allegato666.iloc[0,8] + # st.warning(lingua) + dfx = pd.merge(dfx,df_allegato666, on='Com_code',how='outer') + # st.write('here comes dfxx') + # st.write(dfxx) + + # eliminiamo colonne che non sono richieste e aggiungiamo due colonne che confrontano valori + dfx = dfx.drop(['Comune provenienza bambino','Somma Giorni Assistenza Anno Riferimento 2023', 'Ore totali rendicontate per il 2023','PLZ', 'Bezirk', 'Costo orario', 'Costo del servizio', 'Entrate compartecipazione', 'Ore tariffa maggiorata', 'Entrate maggiorazione'], axis=1) + dfx = dfx.rename(columns={ + #'Conteggio Nr. bimbi ore 666':'Numero bambini report Comuni', + #'Somma Ore Assistenza 666': 'Ore di assistenza report Comuni', + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + + }) + + # il sort dipende dalla lingua dell'allegato 666 + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # facciamo in modo che le colonne siano nell'ordine voluto + columns = dfx.columns.tolist() + columns.insert(1, columns.pop(columns.index('Comune provenienza bambino'))) + columns.insert(2, columns.pop(columns.index('Numero utenti allegato 666'))) + columns.insert(3, columns.pop(columns.index('Numero bambini report Comuni'))) + columns.insert(4, columns.pop(columns.index('Ore di servizio allegato 666'))) + columns.insert(5, columns.pop(columns.index('Ore di assistenza report Comuni'))) + # columns.insert(6, columns.pop(columns.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns] + # sostituiamo i valori NaN o vuoti con zero (0) + dfx = dfx.fillna(0) + + # inseriamo le colonne per il confronto numero bambini e numero ore + # inseriamo un valore booleano + dfx.insert(4,'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7,'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # facciamo le somme + columns_to_sum = ['Numero utenti allegato 666','Numero bambini report Comuni','Ore di servizio allegato 666','Ore di assistenza report Comuni'] + sum_values = dfx[columns_to_sum].sum() + # Create a DataFrame with the sum row for the specified columns + sum_df = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + # For columns not summed, add NaN in the sum row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + riga_vuota = {"Annotazione": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Annotazione": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + < self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime( + "04.09." #modificato 24/6/2024 su richeista RobertaB + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 15.09 dell'anno di nascita + 3 anni" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome","Nome"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum(self): + + # prima vediamo se ci sono bambini in comuni diversi ma con periodi + # che si sovvrappongoni o che sono uguali + # Find codici fiscali present in multiple cities + multi_city_codes = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Self-merge to find overlapping periods in different cities + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define overlap condition + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply condition + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique codes + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[["Cognome", "Nome","Comune","Data inizio contratto (o data inizio assistenza se diversa)","Data fine contratto (o data fine assistenza se diversa)","filename"]].reset_index(drop=True) + result_df = result_df.sort_values(by=["Cognome","Nome"]) + + # st.warning(result_codes) + + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + + # try: + # # non facciamo altro che salvare il file in caso di problemi + # self.df.to_excel("gesamtstd.xlsx") + # except Exception as e: + # st.error(f"Error writing gesamtstf.xlsx; errore {e}") + # if interface.TOLLERANZAZERO: + # st.error("ELaborazione terminata") + # st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.warning("Attenzione: i seguenti bambini non sono stati considerati per il controllo poiche' hanno periodi uguali o sovvraposti per comuni divesi") + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome","Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome","Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + (self.df["Cognome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + & + (self.df["Nome"].str.contains("[@_!#$%^&*()<>?/|}{~:]")) + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome","Nome"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto (o data fine assistenza se diversa)", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome","Nome"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome","Nome"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + st.info(f"Sto elaborando {file.name}...") + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + #"Com_code" + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + + + #st.write(codice_comune) + #st.write(codice_ente) + #st.write(df_gemeinden) + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + #st.write(df) + #st.write(df) + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + #st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + #st.write("") + #st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + # df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + #st.write(df) + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + #st.write(df) + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + return df + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str): + year_part = str(date_str).split('-')[-3] + #st.write(year_part) # Get the year part, which is after the last '.' + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df, date_column,file): + #st.write(date_column) + #st.write(df) + #df[date_column]= pd.to_datetime(df[date_column]).dt.strftime('%d-%m-%Y') + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + #st.write(df) + + #mask = df[date_column].apply(self.is_incorrect_year) + #incorrect_dates_df = df[mask] + #st.write("\nAnno invalido") + #st.write(incorrect_dates_df) + #invalid_dates_df_2 = df["Parsed Date"].where(df["Parsed Date"].dt.year.between(*valid_year_range), pd.NaT) + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty:# or not invalid_dates_df_2.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + #st.write(df) + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + + #if hasattr(caricaEtControlla,self.data): + return self.data + #else: + # st.error("") + # st.error("IMPOSSIBILE PROSEGUIRE!") + # st.stop() + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + #df_gemeinden = df_gemeinden[df_gemeinden['Com_code'] < 118] + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.31_2023_NuevaEdition.py.old" "b/pages/01_TagesMu\314\210tter_ver.3.31_2023_NuevaEdition.py.old" new file mode 100644 index 0000000000000000000000000000000000000000..c0d0941dff146affb461720b12eba4424b10ffc5 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.31_2023_NuevaEdition.py.old" @@ -0,0 +1,3941 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +from io import BytesIO +from typing import Optional, List, Dict, Any +import re + +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import inch, cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.pdfgen import canvas +from reportlab.platypus import Image + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + ERRORDICT = {"2023": ERRORDICT2023} + + # Define a mapping from error keys to relevant emojis + ERROR_ICONS: Dict[str, str] = { + "errCodFisc1": "🧾", # Receipt + "errCodFisc2": "📅", # Calendar + "errAgeChild": "👶", # Baby + "errInizioMinoreFine": "🔄", # Repeat + "errFineAssistenzaMax4Anni": "⏳", # Hourglass + "errKindergarten": "🏫", # School + "errGesamtstundenVertragszeitraum": "⏰", # Alarm Clock + "errSuperatoOreMassime1920": "📊", # Bar Chart + "errBambinoInPiuComuni": "📍", # Location Pin + "errPresentiAnnotazioni": "📝", # Memo + "errOreRendicontateZero": "❌", # Cross Mark + "errCalcoloNumeroBimbi": "📋", # Clipboard + #"errNomeComuneTagesmutter": "🏠", # House + "errDateAnnoRiferimento": "📆", # Tear-Off Calendar + } + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.3-2023-ng)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + #self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + c1,c2 = st.columns(2) + self.choose_files(c1) + self.choose_allegato666(c2) + self.choose_checks() + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self, c1) -> None: + """Allow users to upload multiple Excel files for checking.""" + self.uploaded_files: List[FileUploadBase] = c1.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self, c2) -> None: + """ + Allow users to upload the Allegato 666 file for checking. + + Args: + None + + Returns: + None + """ + self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks" + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate(self.ERRORDICT.items()): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox" + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, 'TOLLERANZAZERO', False) or getattr(self, 'DEBUGWARNINGS', False): + st.error("Elaborazione interrotta") + st.stop() + + + def make_tabs(self) -> None: + """ + Creates tabs for the app. + + The tabs include 'INTEGRITÀ DATI', 'ERRORI e INCONGRUENZE RISCONTRATI', and 'TABELLE FINALI'. + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + +class ReportGenerator: + def __init__(self, df: pd.DataFrame, + df_bambini_che_impediscono_controllo_superamento_ore: pd.DataFrame, + error_dict: dict): + self.df = df + self.df_bambini = df_bambini_che_impediscono_controllo_superamento_ore + self.ERRORDICT = error_dict + + def genera_report(self) -> None: + """ + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + """ + try: + error_keys, errors_present = self._filter_errors(excluded_error="errMassimo543") + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + nr_bambini = self._compute_unique_children() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + excel_data = self._generate_excel_report(nr_bambini, errors_present) + pdf_data = self._generate_pdf_report(nr_bambini, errors_present) + + self._provide_downloads(excel_data, pdf_data) + + st.success("Generato file riassunto analisi") + except Exception as e: + st.error(f"Si è verificato un errore durante la generazione del report: {e}") + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + + def _filter_errors(self, excluded_error: str): + """ + Excludes a specific error from the error dictionary and computes present errors. + + Returns: + Tuple[List[str], Dict[str, int]]: Filtered error keys and errors with counts > 0. + """ + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + if not error_keys: + return error_keys, {} + + error_counts = self.df[error_keys].sum() + errors_present = error_counts[error_counts > 0].to_dict() + #st.write(errors_present) + return error_keys, errors_present + + def _compute_unique_children(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Codice fiscale"].nunique() + + def _generate_excel_report(self, nr_bambini: int, errors_present: dict) -> bytes: + """ + Generates the Excel report and returns the binary data. + """ + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + self._write_excel_summary(worksheet, nr_bambini, errors_present, workbook) + self._write_excel_detailed_sections(worksheet, errors_present, workbook) + return excel_buffer.getvalue() + + def _write_excel_summary(self, worksheet, nr_bambini: int, errors_present: dict, workbook): + """ + Writes the summary section of the Excel report. + """ + #st.write(errors_present) + # Define formats + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 16}) + + # Initialize row and column + row, col = 1, 0 # Starting from row 1 as row 0 is typically reserved + + # Title + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + row += 2 + + # Number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini", bold_format) + row += 2 + + # Error counts + for error_key, count in errors_present.items(): + #st.write(error_key) + error_description = self.ERRORDICT.get(error_key, error_key) + #st.write(error_description) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}", + bold_format + ) + row += 1 + row += 2 # Blank row + + # Additional DataFrame + if not self.df_bambini.empty: + worksheet.write( + row, col, + "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", + bold_format + ) + row += 1 + + # Write column headers + for header_col, header in enumerate(self.df_bambini.columns): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths + worksheet.set_column(0, len(self.df_bambini.columns)-1, 20) + + # Write data rows + for _, r in self.df_bambini.iterrows(): + for header_col, header in enumerate(self.df_bambini.columns): + value = r.get(header, "") + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + row += 3 # Blank rows + + def _write_excel_detailed_sections(self, worksheet, errors_present: dict, workbook): + """ + Writes detailed sections per error in the Excel report. + """ + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + + row, col = worksheet.dim_rowmax, 0 # Continue from the last used row + row += 2 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write(row, col, error_description, title_format2) + row += 1 + + # Define headers + headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + # Set Column Widths Dynamically + for header_col, header in enumerate(headers, start=1): + max_length = max( + self.df[header].astype(str).map(len).max(), + len(header) + ) + 2 + worksheet.set_column(col + header_col, col + header_col, max_length) + + # Filter DataFrame for current error + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + # Write data rows + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Codice fiscale", "")) + + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita) and isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) if pd.notnull(data_nascita) else "" + worksheet.write(row, col + 3, data_nascita_str) + worksheet.write(row, col + 4, r.get("Comune", "")) + row += 1 + row += 3 # Blank rows after each error section + + def _generate_pdf_report(self, nr_bambini: int, errors_present: dict) -> bytes: + """ + Generates the PDF report and returns the binary data. + """ + pdf_buffer = BytesIO() + pdf = SimpleDocTemplate( + pdf_buffer, + pagesize=A4, + rightMargin=2*cm, + leftMargin=2*cm, + topMargin=2*cm, + bottomMargin=2*cm + ) + elements = [] + styles = self._get_pdf_styles() + + # Title + elements.append(Paragraph("Riassunto Analisi Elenchi Tagesmuetter", styles['TitleStyle'])) + elements.append(Spacer(1, 12)) + + # Number of children + elements.append(Paragraph(f"Sono stati elaborati i dati di {nr_bambini} bambini", styles['BodyStyle'])) + elements.append(Spacer(1, 12)) + + # Error Counts + elements.append(Paragraph("Errori e incongruenze rilevati:", styles['HeadingStyle'])) + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph( + f"Trovate {int(count)} occorrenze per il controllo {error_description}", + styles['BodyStyle'] + )) + elements.append(Spacer(1, 6)) + elements.append(Spacer(1, 12)) + + # Additional DataFrame Section + additional_df = self._prepare_additional_df() + if not additional_df.empty: + elements.append(Paragraph( + "Bambini per i quali non è possibile eseguire il controllo superamento ore nel periodo contrattuale", + styles['HeadingStyle'] + )) + elements.append(Spacer(1, 12)) + + table = self._create_pdf_table( + additional_df, + col_widths=[3*cm, 3*cm, 3*cm, 3*cm], + font_size=8 + ) + elements.append(table) + elements.append(Spacer(1, 24)) + + # Detailed Sections + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph(error_description, styles['HeadingStyle'])) + elements.append(Spacer(1, 12)) + + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + table = self._create_pdf_table( + df_bambini[["Cognome", "Codice fiscale", "Data di nascita", "Comune"]], + headers=["Cognome", "Codice fiscale", "Data di nascita", "Comune"], + font_size=8 + ) + elements.append(table) + elements.append(Spacer(1, 24)) + + pdf.build(elements) + return pdf_buffer.getvalue() + + def _get_pdf_styles(self): + """ + Defines and returns custom styles for the PDF. + """ + styles = getSampleStyleSheet() + styles.add(ParagraphStyle( + name='TitleStyle', + fontSize=16, + leading=20, + alignment=TA_CENTER, + spaceAfter=20, + fontName='Helvetica-Bold' + )) + styles.add(ParagraphStyle( + name='HeadingStyle', + fontSize=14, + leading=18, + spaceAfter=10, + fontName='Helvetica-Bold', + alignment=TA_LEFT + )) + styles.add(ParagraphStyle( + name='NormalBold', + fontSize=12, + leading=15, + fontName='Helvetica-Bold', + alignment=TA_LEFT + )) + styles.add(ParagraphStyle( + name='BodyStyle', + fontSize=12, + leading=15, + alignment=TA_LEFT + )) + styles.add(ParagraphStyle( + name='SmallBodyStyle', + fontSize=10, + leading=12, + alignment=TA_LEFT, + spaceAfter=10 + )) + return styles + + def _prepare_additional_df(self) -> pd.DataFrame: + """ + Prepares the additional DataFrame for the PDF report by renaming and dropping columns. + """ + additional_df = self.df_bambini.copy() + + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio' + column_list[4] = 'Data Fine' + # Assign back to additional_df.columns + additional_df.columns = column_list + # Position of the column to delete (e.g., 2 for the third column 'C') + position_to_delete = 5 + + position_to_delete = 5 # Adjust based on actual column index + if position_to_delete < len(additional_df.columns): + column_name = additional_df.columns[position_to_delete] + additional_df.drop(columns=column_name, inplace=True) + + return additional_df + + def _create_pdf_table(self, df: pd.DataFrame, headers: list = None, col_widths: list = None, font_size: int = 10) -> Table: + """ + Converts a DataFrame into a ReportLab Table with styling. + """ + if headers is None: + headers = df.columns.tolist() + data = [headers] + df.fillna("").values.tolist() + + table = Table(data, repeatRows=1, hAlign='LEFT', colWidths=col_widths) + table_style = TableStyle([ + ('BACKGROUND', (0,0), (-1,0), colors.lightgrey), + ('TEXTCOLOR', (0,0), (-1,0), colors.black), + ('ALIGN', (0,0), (-1,-1), 'CENTER'), + ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), + ('FONTSIZE', (0,0), (-1,-1), font_size), + ('BOTTOMPADDING', (0,0), (-1,0), 4), + ('GRID', (0,0), (-1,-1), 0.5, colors.black), + ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), + ]) + table.setStyle(table_style) + return table + + @st.fragment() + def _provide_downloads(self, excel_data: bytes, pdf_data: bytes): + """ + Provides download buttons for the generated Excel and PDF reports. + """ + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + pdf_file_name = f"riassuntoAutomatico_{timestamp}.pdf" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + with col2: + st.download_button( + label="📄 Scarica report PDF", + data=pdf_data, + file_name=pdf_file_name, + mime="application/pdf", + key="fileRiassuntoPDF", + ) + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Converts date columns in a DataFrame to string format. + Args: + df: A pandas DataFrame containing date columns to be converted. + + Returns: + df: The modified DataFrame with date columns formatted as strings. + """ + try: + # Convert 'Data di nascita' column + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + + # Convert 'Data fine contratto (o data fine assistenza se diversa)' column + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + + # Convert 'Data inizio contratto (o data inizio assistenza se diversa)' column + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Generates and displays a grid using the provided DataFrame. + + Args: + dff: A pandas DataFrame to be displayed in the grid. + k: A unique key for the component. + + Returns: + None + """ + + # Drop unnecessary columns from the DataFrame + dff = self.drop_columns(dff) + + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Builds and returns a GridOptions object from the given DataFrame. + Args: + data: A pandas DataFrame containing the data to be displayed in the grid. + Returns: + gridOptions: A GridOptions object configured with the specified data. + """ + + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Drops specified columns from the DataFrame. + Args: + df: A pandas DataFrame from which columns will be dropped. + + Returns: + df: The modified DataFrame with specified columns removed. + """ + + # Drop columns based on keys in ERRORDICT + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop() + + # Drop additional columns for specific year + if self.ANNO_RIFERIMENTO == "2020": + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + @st.fragment() + def download_excel_file( + self, + dftosave: pd.DataFrame, + nome_file: str, + flag: Optional[str] = None + ) -> None: + """ + Downloads an Excel file from the given DataFrame. + + Args: + dftosave (pd.DataFrame): A pandas DataFrame containing the data to be saved. + nome_file (str): The name of the file to save. + flag (Optional[str]): An optional flag to determine whether to drop columns with errors or not. + + Returns: + None + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop(columns=['Colonna_L_da_cancellare_dopo'], errors='ignore') + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f'{timestamp}_{nome_file}' + + # Step 3: Drop columns based on the flag + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def make_df_solo_errori(self) -> None: + """ + Creates a DataFrame containing only records with errors. + Returns: + None + """ + + self.dffinal: pd.DataFrame = self.df + # Create logical condition + # at least one error per error type + for e in self.ERRORDICT.keys(): + # do not want this column in the "error" df as there are too many of them + if e == "errMassimo543": + continue + # first instance of "condition" + # this way, it is created with the correct type + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione: pd.Series = self.dffinal[e] == True + else: + # simple solution: concatenate conditions for checks made + condizione: pd.Series = condizione | self.dffinal[e] == True + + # create df with only records with error + self.dffinal = self.dffinal[condizione] + + # pointless since we do not use this script for 2020 + if self.ANNO_RIFERIMENTO == "2020": + # drop the column we do not want + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + """ + def genera_report(self) -> None: + # + Generates a detailed report in Excel format and provides a CSV download via Streamlit. + + The method performs the following steps: + 1. Excludes specific errors from the analysis. + 2. Computes summary statistics. + 3. Inserts an additional DataFrame into the report. + 4. Generates an Excel report with summaries and detailed error sections. + 5. Constructs a CSV summary directly from the computed data. + 6. Provides download buttons for both Excel and CSV reports. + + Returns: + None + # + try: + # Step 1: Exclude 'errMassimo543' from ERRORDICT + excluded_error = "errMassimo543" + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + # Step 2: Compute number of unique children + nr_bambini = self.df["Codice fiscale"].nunique() + + # Step 3: Precompute error counts using vectorized operations + error_counts = self.df[error_keys].sum() + # Filter errors with at least one occurrence + errors_present = error_counts[error_counts > 0].to_dict() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + # Step 4: Initialize lists for CSV content + csv_lines = [ + "Riassunto analisi", + "", + f"Sono stati elaborati i dati di {nr_bambini} bambini", + "" + ] + + # Step 5: Add error counts to CSV + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + line = f"Trovate {int(count)} occorrenze per il controllo {error_description}" + csv_lines.append(line) + csv_lines.append("") # Blank line + + # Step 6: Insert additional DataFrame into the report (before detailed sections) + additional_df = self.df_bambini_che_impediscono_controllo_superamento_ore + if not additional_df.empty: + # Add heading to CSV + csv_lines.append("Bambini per i quali non e' possibile eseguire il controllo superamento ore") + csv_lines.append("") + # Convert the additional DataFrame to CSV format with semicolon delimiter + additional_csv = additional_df.to_csv(sep=';', index=False) + csv_lines.append(additional_csv) + csv_lines.append("") # Blank line + + # Step 7: Prepare detailed sections for CSV + detailed_csv_sections = [] + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + detailed_csv_sections.append(error_description) + detailed_csv_sections.append("") # Blank line + detailed_csv_sections.append("Cognome;Codice fiscale;Data di nascita;Comune") + # Filter DataFrame for current error and sort + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + for _, r in df_bambini.iterrows(): + cognome = r.get("Cognome", "") + codice_fiscale = r.get("Codice fiscale", "") + data_nascita = r.get("Data di nascita", "") + # Format date as string + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + comune = r.get("Comune", "") + detailed_csv_sections.append(f"{cognome};{codice_fiscale};{data_nascita_str};{comune}") + detailed_csv_sections.append("") # Blank line after each error section + + # Append detailed sections to main CSV lines + csv_lines.extend(detailed_csv_sections) + + # Step 8: Create the Excel report in-memory + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + + # Define formats + bold_format = workbook.add_format({'bold': True}) + header_format = workbook.add_format({'bold': False, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 16}) # New format for larger header + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + # Optional: Define additional formats if needed + + # Initialize row and column + row = 0 + col = 0 + + row += 1 + # Write header with larger font size + worksheet.write(row, col, "Riassunto analisi", title_format) + row += 2 + + # Write number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini", bold_format) + row += 2 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}", + bold_format # Apply bold formatting + ) + row += 1 + + # Add a blank row + row += 1 + + # Insert the additional DataFrame into the Excel report + if not additional_df.empty: + # Write a heading for the additional DataFrame in bold + worksheet.write(row, col, "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", bold_format) + row += 1 + + # Write column headers + #for header_col, header in enumerate(additional_df.columns, start=0): + # worksheet.write(row, header_col, header, header_format) + row += 1 + # Set fixed column widths (example widths, adjust as needed) + worksheet.set_column(0, len(additional_df.columns)-1, 20) # Sets all columns to width 20 + + # Write data rows + for _, r in additional_df.iterrows(): + for header_col, header in enumerate(additional_df.columns, start=0): + value = r.get(header, "") + # If the value is a datetime object, format it + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + # Add a blank row after the DataFrame + row += 3 + + # Write detailed sections per error + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + + # Write error description in bold + worksheet.write(row, col, error_description, title_format2) + row += 1 + + # Define headers + #headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + #for i, header in enumerate(headers, start=1): + # worksheet.write(row, col + i, header, header_format) + row += 1 + + # Filter DataFrame for current error + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + # Write data rows + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Codice fiscale", "")) + # Format date appropriately, assuming it's a datetime object + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + worksheet.write(row, col + 3, data_nascita_str) + worksheet.write(row, col + 4, r.get("Comune", "")) + row += 1 + # Add a blank row after each error section + row += 3 + + # Step 9: Prepare Excel file for download + excel_buffer.seek(0) + excel_data = excel_buffer.getvalue() + + # Step 10: Convert csv_lines to CSV bytes + csv_content = "\n".join(csv_lines).encode("utf-8-sig") + + # Step 11: Show success message + st.success("Generato file riassunto analisi") + + # Step 12: Provide download buttons for both Excel and CSV with appropriate icons + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report Excel", + data=excel_data, + file_name="riassuntoAutomatico.xlsx", + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + with col2: + st.download_button( + label="📥 Scarica riassunto CSV", + data=csv_content, + file_name="riassuntoAutomaticoDati.csv", + mime="text/csv", + key="fileRiassuntoCSV", + ) + + + except Exception as e: + st.error(f"Si è verificato un errore durante la generazione del report: {e}") + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + """ + """ + @st.fragment() + def genera_report(self) -> None: + # + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + + The method performs the following steps: + 1. Excludes specific errors from the analysis. + 2. Computes summary statistics. + 3. Inserts an additional DataFrame into the report. + 4. Generates an Excel report with summaries and detailed error sections. + 5. Generates a PDF report with similar content and formatting. + 6. Provides download buttons for Excel and PDF reports. + + Returns: + None + # + try: + # Step 1: Exclude 'errMassimo543' from ERRORDICT + excluded_error = "errMassimo543" + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + # Step 2: Compute number of unique children + nr_bambini = self.df["Codice fiscale"].nunique() + + # Step 3: Precompute error counts using vectorized operations + error_counts = self.df[error_keys].sum() + # Filter errors with at least one occurrence + errors_present = error_counts[error_counts > 0].to_dict() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + # **Removed Steps 4-7: CSV Generation** + + # Step 8: Create the Excel report in-memory + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + + # Define formats + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 16}) # Larger header + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) # Sub-headers + + # Initialize row and column + row = 0 + col = 0 + + row += 1 + # Write header with larger font size + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + row += 2 + + # Write number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini", bold_format) + row += 2 + + # Write error counts in bold + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}", + bold_format # Apply bold formatting + ) + row += 1 + + # Add a blank row + row += 1 + + # Insert the additional DataFrame into the Excel report + additional_df = self.df_bambini_che_impediscono_controllo_superamento_ore + if not additional_df.empty: + # Write a heading for the additional DataFrame in bold + worksheet.write(row, col, "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", bold_format) + row += 1 + + # Write column headers + for header_col, header in enumerate(additional_df.columns, start=0): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths (example widths, adjust as needed) + worksheet.set_column(0, len(additional_df.columns)-1, 20) # Sets all columns to width 20 + + # Write data rows + for _, r in additional_df.iterrows(): + for header_col, header in enumerate(additional_df.columns, start=0): + value = r.get(header, "") + # If the value is a datetime object, format it + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + # Add a blank row after the DataFrame + row += 3 + + # Write detailed sections per error + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + + # Write error description in bold + worksheet.write(row, col, error_description, title_format2) + row += 1 + + # Define headers + headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + for i, header in enumerate(headers, start=1): + worksheet.write(row, col + i, header, header_format) + row += 1 + + # Set Column Widths Dynamically for Detailed Sections + for header_col, header in enumerate(headers, start=1): + # Calculate maximum length of the column content + max_length = self.df[header].astype(str).map(len).max() + max_length = max(max_length, len(header)) + 2 # Add a buffer of 2 + worksheet.set_column(col + header_col, col + header_col, max_length) + + # Filter DataFrame for current error + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + # Write data rows + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Codice fiscale", "")) + # Format date appropriately, assuming it's a datetime object + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + worksheet.write(row, col + 3, data_nascita_str) + worksheet.write(row, col + 4, r.get("Comune", "")) + row += 1 + # Add a blank row after each error section + row += 3 + + # Step 9: Prepare Excel file for download + excel_buffer.seek(0) + excel_data = excel_buffer.getvalue() + + # **Removed Step 10: CSV Conversion** + + # Step 11: Generate PDF report + pdf_buffer = BytesIO() + pdf = SimpleDocTemplate( + pdf_buffer, + pagesize=A4, + rightMargin=2*cm, + leftMargin=2*cm, + topMargin=2*cm, + bottomMargin=2*cm + ) + elements = [] + styles = getSampleStyleSheet() + + # Define custom styles + styles.add(ParagraphStyle( + name='TitleStyle', + fontSize=16, + leading=20, + alignment=TA_CENTER, # Center alignment + spaceAfter=20, + fontName='Helvetica-Bold' + )) + styles.add(ParagraphStyle( + name='HeadingStyle', + fontSize=14, + leading=18, + spaceAfter=10, + fontName='Helvetica-Bold', + alignment=TA_LEFT # Left alignment + )) + styles.add(ParagraphStyle( + name='NormalBold', + fontSize=12, + leading=15, + fontName='Helvetica-Bold', + alignment=TA_LEFT # Left alignment + )) + styles.add(ParagraphStyle( + name='BodyStyle', + fontSize=12, + leading=15, + alignment=TA_LEFT # Left alignment + )) + styles.add(ParagraphStyle( + name='SmallBodyStyle', + fontSize=10, # Smaller font size + leading=12, + alignment=TA_LEFT, # Right alignment + spaceAfter=10 + )) + + # Optional: Add Logo + #try: + # logo = Image("path_to_logo.png", width=2*inch, height=2*inch) + # logo.hAlign = 'RIGHT' # Align the logo to the right + # elements.append(logo) + # elements.append(Spacer(1, 12)) + #except Exception as img_e: + # st.warning(f"Impossibile caricare il logo: {img_e}") + + # Title + elements.append(Paragraph("Riassunto Analisi", styles['TitleStyle'])) + elements.append(Spacer(1, 12)) + + # Number of children + elements.append(Paragraph(f"Sono stati elaborati i dati di {nr_bambini} bambini", styles['BodyStyle'])) + elements.append(Spacer(1, 12)) + + # Error Counts + elements.append(Paragraph("Errori e incongruenze rilevati:", styles['HeadingStyle'])) + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph(f"Trovate {int(count)} occorrenze per il controllo {error_description}", styles['NormalBold'])) + elements.append(Spacer(1, 6)) + + elements.append(Spacer(1, 12)) + + # Additional DataFrame Section with Right Alignment and Smaller Font + additional_df = self.df_bambini_che_impediscono_controllo_superamento_ore + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio' + column_list[4] = 'Data Fine' + # Assign back to additional_df.columns + additional_df.columns = column_list + # Position of the column to delete (e.g., 2 for the third column 'C') + position_to_delete = 5 + + # Get the column name + column_name = additional_df.columns[position_to_delete] + + # Drop the column + additional_df = additional_df.drop(columns=column_name) + + if not additional_df.empty: + elements.append(Paragraph( + "Bambini per i quali non è possibile eseguire il controllo superamento ore nel periodo contrattuale", + styles['HeadingStyle'] + )) + elements.append(Spacer(1, 12)) + + # Converti DataFrame in lista di liste per la tabella + data = [additional_df.columns.tolist()] + additional_df.values.tolist() + + # Definisci larghezze delle colonne (adatta secondo necessità) + col_widths = [3*cm, 3*cm, 3*cm, 3*cm] # Adatta le dimensioni delle colonne + + table = Table(data, repeatRows=1, hAlign='LEFT', colWidths=col_widths) + + # Definisci lo stile della tabella con dimensione del font ridotta e avvolgimento del testo + table_style = TableStyle([ + ('BACKGROUND', (0,0), (-1,0), colors.lightgrey), + ('TEXTCOLOR',(0,0),(-1,0),colors.black), + ('ALIGN',(0,0),(-1,-1),'CENTER'), + ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), + ('FONTSIZE', (0,0), (-1,-1), 8), # Riduci ulteriormente la dimensione del font + ('TOPPADDING', (0,0), (-1,-1), 1), # Riduci il padding + ('BOTTOMPADDING', (0,0), (-1,-1), 1), + ('LEFTPADDING', (0,0), (-1,-1), 2), + ('RIGHTPADDING', (0,0), (-1,-1), 2), + ('GRID', (0,0), (-1,-1), 0.25, colors.black), # Linee più sottili + #('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.whitesmoke, colors.lightyellow]), + ('VALIGN', (0,0), (-1,-1), 'MIDDLE'), # Allinea verticalmente al centro + #('WORDWRAP', (0,0), (-1,-1)), # Abilita l'avvolgimento del testo + ]) + table.setStyle(table_style) + + elements.append(table) + elements.append(Spacer(1, 24)) + + # Detailed Sections + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph(error_description, styles['HeadingStyle'])) + elements.append(Spacer(1, 12)) + + # Prepare data for table + headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + data = [headers] + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + for _, r in df_bambini.iterrows(): + cognome = r.get("Cognome", "") + codice_fiscale = r.get("Codice fiscale", "") + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + comune = r.get("Comune", "") + data.append([cognome, codice_fiscale, data_nascita_str, comune]) + + # Create Table + table = Table(data, repeatRows=1, hAlign='LEFT') # Default left alignment + + table_style = TableStyle([ + ('BACKGROUND', (0,0), (-1,0), colors.lightgrey), + ('TEXTCOLOR',(0,0),(-1,0),colors.black), + ('ALIGN',(0,0),(-1,-1),'LEFT'), + ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), + ('FONTSIZE', (0,0), (-1,-1), 8), + ('BOTTOMPADDING', (0,0), (-1,0), 4), + ('GRID', (0,0), (-1,-1), 0.5, colors.black), + #('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.whitesmoke, colors.lightyellow]), + ]) + table.setStyle(table_style) + + elements.append(table) + elements.append(Spacer(1, 24)) + + # Build PDF without Page Numbering + pdf.build(elements) # Removed 'canvasmaker=NumberedCanvas' + pdf_buffer.seek(0) + pdf_data = pdf_buffer.getvalue() + + # Step 12: Show success message + st.success("Generato file riassunto analisi") + + # Step 13: Provide download buttons for Excel and PDF with appropriate icons + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + pdf_file_name = f"riassuntoAutomatico_{timestamp}.pdf" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + with col2: + st.download_button( + label="📄 Scarica report PDF", + data=pdf_data, + file_name=pdf_file_name, + mime="application/pdf", + key="fileRiassuntoPDF", + ) + + except Exception as e: + st.error(f"Si è verificato un errore durante la generazione del report: {e}") + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + """ + + """ + def genera_report(self) -> None: + # + Generates detailed reports in Excel, CSV, and PDF formats and provides download options via Streamlit. + + The method performs the following steps: + 1. Excludes specific errors from the analysis. + 2. Computes summary statistics. + 3. Inserts an additional DataFrame into the report. + 4. Generates an Excel report with summaries and detailed error sections. + 5. Constructs a CSV summary directly from the computed data. + 6. Generates a PDF report with similar content and formatting. + 7. Provides download buttons for Excel, CSV, and PDF reports. + + Returns: + None + # + try: + # Step 1: Exclude 'errMassimo543' from ERRORDICT + excluded_error = "errMassimo543" + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + # Step 2: Compute number of unique children + nr_bambini = self.df["Codice fiscale"].nunique() + + # Step 3: Precompute error counts using vectorized operations + error_counts = self.df[error_keys].sum() + # Filter errors with at least one occurrence + errors_present = error_counts[error_counts > 0].to_dict() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + # Step 4: Initialize lists for CSV content + csv_lines = [ + "Riassunto analisi", + "", + f"Sono stati elaborati i dati di {nr_bambini} bambini", + "" + ] + + # Step 5: Add error counts to CSV + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + line = f"Trovate {int(count)} occorrenze per il controllo {error_description}" + csv_lines.append(line) + csv_lines.append("") # Blank line + + # Step 6: Insert additional DataFrame into the report (before detailed sections) + additional_df = self.df_bambini_che_impediscono_controllo_superamento_ore + if not additional_df.empty: + # Add heading to CSV + csv_lines.append("Bambini per i quali non e' possibile eseguire il controllo superamento ore") + csv_lines.append("") + # Convert the additional DataFrame to CSV format with semicolon delimiter + additional_csv = additional_df.to_csv(sep=';', index=False) + csv_lines.append(additional_csv) + csv_lines.append("") # Blank line + + # Step 7: Prepare detailed sections for CSV + detailed_csv_sections = [] + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + detailed_csv_sections.append(error_description) + detailed_csv_sections.append("") # Blank line + detailed_csv_sections.append("Cognome;Codice fiscale;Data di nascita;Comune") + # Filter DataFrame for current error and sort + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + for _, r in df_bambini.iterrows(): + cognome = r.get("Cognome", "") + codice_fiscale = r.get("Codice fiscale", "") + data_nascita = r.get("Data di nascita", "") + # Format date as string + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + comune = r.get("Comune", "") + detailed_csv_sections.append(f"{cognome};{codice_fiscale};{data_nascita_str};{comune}") + detailed_csv_sections.append("") # Blank line after each error section + + # Append detailed sections to main CSV lines + csv_lines.extend(detailed_csv_sections) + + # Step 8: Create the Excel report in-memory + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + + # Define formats + bold_format = workbook.add_format({'bold': True}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 16}) # New format for larger header + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + # Optional: Define additional formats if needed + + # Initialize row and column + row = 0 + col = 0 + + row += 1 + # Write header with larger font size + worksheet.write(row, col, "Riassunto analisi", title_format) + row += 2 + + # Write number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini", bold_format) + row += 2 + + # Write error counts in bold + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}", + bold_format # Apply bold formatting + ) + row += 1 + + # Add a blank row + row += 1 + + # Insert the additional DataFrame into the Excel report + if not additional_df.empty: + # Write a heading for the additional DataFrame in bold + worksheet.write(row, col, "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", bold_format) + row += 1 + + # Write column headers + for header_col, header in enumerate(additional_df.columns, start=0): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths (example widths, adjust as needed) + worksheet.set_column(0, len(additional_df.columns)-1, 20) # Sets all columns to width 20 + + # Write data rows + for _, r in additional_df.iterrows(): + for header_col, header in enumerate(additional_df.columns, start=0): + value = r.get(header, "") + # If the value is a datetime object, format it + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + # Add a blank row after the DataFrame + row += 3 + + # Write detailed sections per error + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + + # Write error description in bold + worksheet.write(row, col, error_description, title_format2) + row += 1 + + # Define headers + headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + for i, header in enumerate(headers, start=1): + worksheet.write(row, col + i, header, header_format) + row += 1 + + # Set Column Widths Dynamically for Detailed Sections + for header_col, header in enumerate(headers, start=1): + # Calculate maximum length of the column content + max_length = self.df[header].astype(str).map(len).max() + max_length = max(max_length, len(header)) + 2 # Add a buffer of 2 + worksheet.set_column(col + header_col, col + header_col, max_length) + + # Filter DataFrame for current error + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + # Write data rows + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Codice fiscale", "")) + # Format date appropriately, assuming it's a datetime object + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + worksheet.write(row, col + 3, data_nascita_str) + worksheet.write(row, col + 4, r.get("Comune", "")) + row += 1 + # Add a blank row after each error section + row += 3 + + # Step 9: Prepare Excel file for download + excel_buffer.seek(0) + excel_data = excel_buffer.getvalue() + + # Step 10: Convert csv_lines to CSV bytes + csv_content = "\n".join(csv_lines).encode("utf-8-sig") + + # Step 11: Generate PDF report + pdf_buffer = BytesIO() + pdf = SimpleDocTemplate(pdf_buffer, pagesize=A4) + elements = [] + styles = getSampleStyleSheet() + # Define custom styles + styles.add(ParagraphStyle(name='TitleStyle', fontSize=16, leading=20, alignment=1, spaceAfter=20, fontName='Helvetica-Bold')) + styles.add(ParagraphStyle(name='HeadingStyle', fontSize=14, leading=18, spaceAfter=10, fontName='Helvetica-Bold')) + styles.add(ParagraphStyle(name='NormalBold', fontSize=12, leading=15, fontName='Helvetica-Bold')) + styles.add(ParagraphStyle(name='BodyStyle', fontSize=12, leading=15)) # Renamed from 'Normal' + + # Title + elements.append(Paragraph("Riassunto Analisi", styles['TitleStyle'])) + elements.append(Spacer(1, 12)) + + # Number of children + elements.append(Paragraph(f"Sono stati elaborati i dati di {nr_bambini} bambini", styles['BodyStyle'])) + elements.append(Spacer(1, 12)) + + # Error Counts + elements.append(Paragraph("Controlli Rilevati:", styles['HeadingStyle'])) + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph(f"Trovate {int(count)} occorrenze per il controllo {error_description}", styles['NormalBold'])) + elements.append(Spacer(1, 6)) + + elements.append(Spacer(1, 12)) + + # Additional DataFrame + if not additional_df.empty: + elements.append(Paragraph("Bambini per i quali non è possibile eseguire il controllo superamento ore nel periodo contrattuale", styles['HeadingStyle'])) + elements.append(Spacer(1, 12)) + + # Convert DataFrame to list of lists for Table + data = [additional_df.columns.tolist()] + additional_df.values.tolist() + table = Table(data, repeatRows=1) + + # Add style to the table + table_style = TableStyle([ + ('BACKGROUND', (0,0), (-1,0), colors.lightgrey), + ('TEXTCOLOR',(0,0),(-1,0),colors.black), + ('ALIGN',(0,0),(-1,-1),'CENTER'), + ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), + ('BOTTOMPADDING', (0,0), (-1,0), 12), + ('GRID', (0,0), (-1,-1), 1, colors.black), + ]) + table.setStyle(table_style) + + elements.append(table) + elements.append(Spacer(1, 24)) + + # Detailed Sections + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + elements.append(Paragraph(error_description, styles['HeadingStyle'])) + elements.append(Spacer(1, 12)) + + # Prepare data for table + headers = ["Cognome", "Codice fiscale", "Data di nascita", "Comune"] + data = [headers] + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + for _, r in df_bambini.iterrows(): + cognome = r.get("Cognome", "") + codice_fiscale = r.get("Codice fiscale", "") + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita): + if isinstance(data_nascita, pd.Timestamp): + data_nascita_str = data_nascita.strftime("%d/%m/%Y") + else: + data_nascita_str = str(data_nascita) + else: + data_nascita_str = "" + comune = r.get("Comune", "") + data.append([cognome, codice_fiscale, data_nascita_str, comune]) + + # Create Table + table = Table(data, repeatRows=1) + table_style = TableStyle([ + ('BACKGROUND', (0,0), (-1,0), colors.lightgrey), + ('TEXTCOLOR',(0,0),(-1,0),colors.black), + ('ALIGN',(0,0),(-1,-1),'CENTER'), + ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), + ('BOTTOMPADDING', (0,0), (-1,0), 12), + ('GRID', (0,0), (-1,-1), 1, colors.black), + ]) + table.setStyle(table_style) + + elements.append(table) + elements.append(Spacer(1, 24)) + + # Build PDF + pdf.build(elements) + pdf_buffer.seek(0) + pdf_data = pdf_buffer.getvalue() + + # Step 12: Show success message + st.success("Generato file riassunto analisi") + + # Step 13: Provide download buttons for Excel, CSV, and PDF with appropriate icons + col1, col2, col3 = st.columns(3) + with col1: + st.download_button( + label="📥 Scarica report Excel", + data=excel_data, + file_name="riassuntoAutomatico.xlsx", + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + with col2: + st.download_button( + label="📥 Scarica riassunto CSV", + data=csv_content, + file_name="riassuntoAutomaticoDati.csv", + mime="text/csv", + key="fileRiassuntoCSV", + ) + with col3: + st.download_button( + label="📄 Scarica report PDF", + data=pdf_data, + file_name="riassuntoAutomatico.pdf", + mime="application/pdf", + key="fileRiassuntoPDF", + ) + + except Exception as e: + st.error(f"Si è verificato un errore durante la generazione del report: {e}") + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + """ + + @st.fragment() + def display_final_table(self) -> None: + """ + Displays the final table with all data and a separate table for errors only. + + This method creates two expanders: one for displaying all data in a grid format, + and another for showing only records that contain errors. It also provides options + to download these tables as Excel files. + + Args: + None + + Returns: + None + """ + no_zero = NO_ZERO # Assuming this is defined somewhere else in the code. + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file( + self.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + gridOptions = self.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)") + with expndr: + self.make_df_solo_errori() + + self.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + gridOptions = self.buildGrid(self.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error(f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error(f"La funzione {check} non è stata eseguita; errore generico: {e}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.ERRORDICT) + reportmaker.genera_report() + self.display_final_table() + + """ + def check_data(self) -> None: + # + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + # + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name: str = f"Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + try: + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + + # Create an expander for the final table + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + self.download_excel_file( + self.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + # Build and display the grid for all data + gridOptions = self.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + # Create a DataFrame with only errors and display it + self.make_df_solo_errori() + + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)") + with expndr: + self.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + # Build and display the grid for errors only + gridOptions = self.buildGrid(self.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + st.write("") + + try: + # Save the final DataFrame with errors to an Excel file + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + """ + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + """ + def errCodFisc2(self) -> None: + # METTI virgolette + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + # METTI virgolette + try: + # Step 1: Validate the format of "Codice fiscale" using regex + # The fiscal code should follow the pattern: 6 letters, 2 digits, 1 letter, 2 digits, 1 letter, 3 digits, 1 letter + codice_fiscale_pattern: str = ( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False + ) + + # Step 2: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df[codvalido].copy() + + # Step 3: Determine gender based on "Codice fiscale" + # In Italian fiscal codes, characters 10-11 encode the day of birth: + # - For males: 01-31 + # - For females: 41-71 (day + 40) + # Extract the day of birth portion + giorno_nascita: pd.Series = dfcod["Codice fiscale"].str[9:11].astype(int) + + # Logical conditions for gender determination + ggnot40: pd.Series = giorno_nascita < 40 # Males + g40: pd.Series = giorno_nascita >= 40 # Females + + # Step 4: Validate the day of birth for females + # For females, subtract 40 from the encoded day to get the actual day + gg40: pd.Series = pd.to_datetime( + dfcod.loc[g40, "Data di nascita"], errors="coerce" + ).dt.day == (giorno_nascita[g40] - 40) + + # Step 5: Validate the day of birth for males + gg: pd.Series = ( + pd.to_datetime( + dfcod.loc[ggnot40, "Data di nascita"], errors="coerce" + ).dt.day + == giorno_nascita[ggnot40] + ) + + # Step 6: Validate the year of birth encoded in "Codice fiscale" + # The year is encoded in characters 7-8 and represents the last two digits of the year + anno_nascita_codfisc: pd.Series = 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + anno_nascita_reale: pd.Series = dfcod["Data di nascita"].dt.year + anno: pd.Series = anno_nascita_reale == anno_nascita_codfisc + + # Step 7: Validate the month of birth encoded in "Codice fiscale" + # The month is encoded in character 9 with letters A-T (excluding some) + # Mapping letters to month numbers + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + # Extract the month character and map to integers + mese_codfisc: pd.Series = ( + dfcod["Codice fiscale"].str[8].str.upper().map(mese_mapping) + ) + mese_reale: pd.Series = dfcod["Data di nascita"].dt.month + mese: pd.Series = mese_reale == mese_codfisc + + # Step 8: Identify records with any inconsistencies + # Conditions where: + # - The month does not match + # - The day does not match for males + # - The day does not match for females + # - The year does not match + condizione_errori: pd.Series = ~mese | ~gg | ~gg40 | ~anno + + # Step 9: Check if any errors are found + if condizione_errori.any(): + num_errori: int = condizione_errori.sum() + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati." + ) + + # Step 10: Concatenate all error conditions into a single DataFrame + frames: List[pd.DataFrame] = [ + dfcod.loc[g40 & ~gg40], # Females with day mismatch + dfcod.loc[ggnot40 & ~gg], # Males with day mismatch + dfcod.loc[~mese], # Month mismatch + dfcod.loc[~anno], # Year mismatch + ] + results: pd.DataFrame = pd.concat(frames).drop_duplicates() + + # Step 11: Convert date columns to strings if required by the interface + if ( + hasattr(interface, "CONVERTIDATESTRINGHE") + and interface.CONVERTIDATESTRINGHE + ): + results = self.converti_date_in_stringhe(results) + + # Step 12: Provide an option to download the error data as an Excel file + self.download_excel_file( + results.sort_values(by=["Cognome", "Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + + # Step 13: Display the error data in an interactive grid within Streamlit + self.make_grid( + results.sort_values(by=["Cognome", "Nome"]), "errCodFisc2x" + ) + + # Step 14: Flag the erroneous records in the main DataFrame + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + """ + """ + def errCodFisc2(self) -> None: + # + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + # + + + # Precompile the regex pattern + codice_fiscale_pattern_compiled: re.Pattern = re.compile(r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$") + + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern_compiled, + na=False + ) + + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod: pd.DataFrame = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40: pd.Series = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40: pd.Series = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40: pd.DataFrame = dfcod[g40] + dfnot40: pd.DataFrame = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40: pd.Series = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg: pd.Series = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno: pd.Series = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese: pd.Series = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames: List[pd.DataFrame] = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results: pd.DataFrame = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome","Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome","Nome"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + """ + + def errCodFisc2(self) -> None: + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, + na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors='coerce') + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & (actual_day != (giorno_nascita_code - 40)) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "H": 6, + "L": 7, "M": 8, "P": 9, "R": 10, "S": 11, "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, "G": 99, "I": 99, "J": 99, "K": 99, "N": 99, + "O": 99, "Q": 99, "U": 99, "V": 99, "W": 99, "X": 99, + "Y": 99, "Z": 99 + } + + mese_codice: pd.Series = cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + errors_mask: pd.Series = ( + day_mismatch_male | + day_mismatch_female | + month_mismatch | + year_mismatch + ) + + # Step 9: Check if any errors are found + if errors_mask.any(): + num_errori: int = errors_mask.sum() + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati." + ) + + # Step 10: Filter error records + results: pd.DataFrame = dfcod.loc[errors_mask].copy() + + # Step 11: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + # Step 12: Provide downloadable Excel file + self.download_excel_file( + results.sort_values(by=["Cognome", "Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + + # Step 13: Display the error data in an interactive grid within Streamlit + self.make_grid( + results.sort_values(by=["Cognome", "Nome"]), + "errCodFisc2x" + ) + + # Step 14: Flag the erroneous records in the main DataFrame + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + + def errCalcoloNumeroBimbi(self) -> None: + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ind] > 0: + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by='Com_code', ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on='Com_code', how='outer') + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[0, 8] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on='Com_code', how='outer') + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + 'Comune provenienza bambino', + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + 'PLZ', + 'Bezirk', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione' + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename(columns={ + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + }) + + # Step 12: Sort and rename columns based on the language code + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert(1, columns_order.pop(columns_order.index('Comune provenienza bambino'))) + columns_order.insert(2, columns_order.pop(columns_order.index('Numero utenti allegato 666'))) + columns_order.insert(3, columns_order.pop(columns_order.index('Numero bambini report Comuni'))) + columns_order.insert(4, columns_order.pop(columns_order.index('Ore di servizio allegato 666'))) + columns_order.insert(5, columns_order.pop(columns_order.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert(4, 'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7, 'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + 'Numero utenti allegato 666', + 'Numero bambini report Comuni', + 'Ore di servizio allegato 666', + 'Ore di assistenza report Comuni' + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = self.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + self.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "casospeciale" + ) + + # Display the DataFrame in an interactive grid + AgGrid( + dfx, + gridOptions=gridOptions, + enable_enterprise_modules=True + ) + # Note: No flag is set here as it's not required + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica: pd.Series = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(self.df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + condizione_logica: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errIncongruenzaDateAnnoRiferimento", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: + """ + Check if there are any records where the start date of the contract is after the end date. + """ + # Create a boolean condition for when the start date is greater than the end date + inizio_minore_fine: pd.Series = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + + # Combine this condition with NO_ZERO filter + condizione_logica: pd.Series = inizio_minore_fine & NO_ZERO + + # If there are any such records, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + + # Create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + # If required, convert date columns to string format + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + + # Set the flag for errors in the original dataframe + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: + """ + Check if the age of a child is less than 90 days. + Args: + None + Returns: + None + """ + + # Calculate the number of days between the start date and the birthdate + giorni: pd.Series = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + + # Combine the condition with the NO_ZERO filter + condizione_logica: pd.Series = giorni & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_eta_bambino.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errAgeChildx", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errFineAssistenzaMax4Anni(self) -> None: + """ + Check if the end date of assistance is more than 4 years from the birthdate. + Args: + None + Returns: + None + """ + + # Calculate the number of days between the end date and the birthdate + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + # Combine the condition with the NO_ZERO filter + condizione_logica = giorni & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errFineAssistenzaMax4Annix", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten(self) -> None: + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Ensure necessary columns are present + required_columns = { + "Data di nascita", + "Data fine contratto (o data fine assistenza se diversa)", + "Cognome", + "Nome" + } + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError(f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'") + return + + # Convert relevant columns to datetime if not already + self.df["Data di nascita"] = pd.to_datetime( + self.df["Data di nascita"], format="%d.%m.%Y", errors='coerce' + ) + self.df["Data fine contratto (o data fine assistenza se diversa)"] = pd.to_datetime( + self.df["Data fine contratto (o data fine assistenza se diversa)"], format="%d.%m.%Y", errors='coerce' + ) + + # Define control date from constants + controllo_kinder_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + data_nascita: pd.Series = self.df["Data di nascita"] < controllo_kinder_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + birth_year_plus_3: pd.Series = self.df["Data di nascita"].dt.year + 3 + + # Create a Series of "04.09.{birth_year + 3}" as datetime + acceptable_end_date: pd.Series = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), format="%d.%m.%Y", errors='coerce' #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + ) + + # Compare "Data fine contratto..." with the acceptable end date + data_fine_ass: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > acceptable_end_date + + # Step 3: Apply additional condition if reference year is "2020" + if self.ANNO_RIFERIMENTO == "2020": + # Define an additional birth date condition + additional_birth_date_condition: pd.Series = self.df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y", errors='coerce' + ) + # Combine all conditions + condizione_logica: pd.Series = data_nascita & additional_birth_date_condition & data_fine_ass & NO_ZERO + else: + # Combine conditions without the additional birth date condition + condizione_logica: pd.Series = data_nascita & data_fine_ass & NO_ZERO + + # Step 4: Check if any errors are found + if condizione_logica.any(): + num_errori: int = condizione_logica.sum() + expndr = st.expander( + f"Trovato errore Kindergarten ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni" + ) + + # Filter the DataFrame for error records + dftemp: pd.DataFrame = self.df.loc[condizione_logica].copy() + + # Optional: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Provide a downloadable Excel file with sorted error records + dftemp_sorted = dftemp.sort_values(by=["Cognome", "Nome"]) + self.download_excel_file( + dftemp_sorted, + "errori_kindergarten.xlsx", + ) + + # Display the error records in an interactive grid within Streamlit + self.make_grid( + dftemp_sorted, + "errKindergartenx", + ) + + # Flag the erroneous records in the main DataFrame + erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + condizione_logica, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge( + df_multi, on="Codice fiscale", suffixes=("_1", "_2") + ) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform("sum").astype("float") + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + condizione_logica = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # Create an expandable section in Streamlit to display warnings and information + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errore/i)" + ) + with expndr: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + + # Convert date columns to strings if necessary + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + # Provide options to download the error data as an Excel file + self.download_excel_file( + dfx.sort_values(by=["Cognome", "Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + # Display the error data in a grid format + self.make_grid( + dfx.sort_values(by=["Cognome", "Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + def errSuperatoOreMassime1920(self) -> None: + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920." + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3a: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + # Step 3b: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errSuperatoOreMassime1920x", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + condizione_logica: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 3a: Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_in_piu_comuni.xlsx", + ) + + # Step 3c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errBambinoInPiuComunix", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizione & NO_ZERO + + # Step 3: Check if any records meet the combined condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errPresentiAnnotazionix", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + condizione_logica: pd.Series = ~condizione + + # Step 4: Check if any mismatches exist + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati {self.df[condizione_logica].shape[0]} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if ( + hasattr(interface, "CONVERTIDATESTRINGHE") + and interface.CONVERTIDATESTRINGHE + ): + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + + for file in self.filelist: + c1,c2 = st.columns([3,2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + #c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error(f"Errore durante concatenamento dei dataframe caricati: errore: {e}") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + + if codice_comune not in self.df_gemeinden["Com_code"].values: + #c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato ma l'elaborazione prosegue. \n\rIl nome file e': {file.name}" + ) + flag = 1 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero progressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + flag = 1 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero progressivo"].duplicated(keep=False) + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + #c2.warning("Attenzione!") + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero progressivo", "Cognome", "Nome"] + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Cognome"].isna() & df["Nome"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None + + except Exception as e: + c2.warning("Attenzione!") + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + flag = 1 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None + + except Exception as e: + c2.warning("Attenzione!") + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None + except Exception as e: + c2.warning("Attenzione!") + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + flag = 1 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + #c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split('-')[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df: pd.DataFrame, date_column: str, file) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.x" "b/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..461e55eedff4f45407e36b4d5c57fcfc40921c8e --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.x" @@ -0,0 +1,2763 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +#from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +from io import BytesIO +from typing import Optional, List, Dict, Any +import re + +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import inch, cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.pdfgen import canvas +from reportlab.platypus import Image + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + ERRORDICT = {"2023": ERRORDICT2023} + + # Define a mapping from error keys to relevant emojis + ERROR_ICONS: Dict[str, str] = { + "errCodFisc1": "🧾", # Receipt + "errCodFisc2": "📅", # Calendar + "errAgeChild": "👶", # Baby + "errInizioMinoreFine": "🔄", # Repeat + "errFineAssistenzaMax4Anni": "⏳", # Hourglass + "errKindergarten": "🏫", # School + "errGesamtstundenVertragszeitraum": "⏰", # Alarm Clock + "errSuperatoOreMassime1920": "📊", # Bar Chart + "errBambinoInPiuComuni": "📍", # Location Pin + "errPresentiAnnotazioni": "📝", # Memo + "errOreRendicontateZero": "❌", # Cross Mark + "errCalcoloNumeroBimbi": "📋", # Clipboard + #"errNomeComuneTagesmutter": "🏠", # House + "errDateAnnoRiferimento": "📆", # Tear-Off Calendar + } + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.6)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + #self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + c1,c2 = st.columns(2) + self.choose_files(c1) + self.choose_allegato666(c2) + self.choose_checks() + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self, c1) -> None: + """Allow users to upload multiple Excel files for checking.""" + self.uploaded_files: List[FileUploadBase] = c1.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self, c2) -> None: + """ + Allow users to upload the Allegato 666 file for checking. + + Args: + None + + Returns: + None + """ + self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks" + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate(self.ERRORDICT.items()): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox" + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, 'TOLLERANZAZERO', False) or getattr(self, 'DEBUGWARNINGS', False): + st.error("Elaborazione interrotta") + st.stop() + + + def make_tabs(self) -> None: + """ + Creates tabs for the app. + + The tabs include 'INTEGRITÀ DATI', 'ERRORI e INCONGRUENZE RISCONTRATI', and 'TABELLE FINALI'. + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + +class ReportGenerator: + def __init__(self, processor, trova_errori, interface): + self.df = trova_errori.df + self.df_bambini = trova_errori.df_bambini_che_impediscono_controllo_superamento_ore + + self.df_calcolo_666 = trova_errori.df_calcolo_666 + self.dffinal = trova_errori.dffinal + + # st.write(self.df_calcolo_666) + + self.ERRORDICT = trova_errori.ERRORDICT + + @st.fragment() + def display_final_table(self) -> None: + """ + Displays the final table with all data and a separate table for errors only. + + This method creates two expanders: one for displaying all data in a grid format, + and another for showing only records that contain errors. It also provides options + to download these tables as Excel files. + + Args: + None + + Returns: + None + """ + no_zero = NO_ZERO # Assuming this is defined somewhere else in the code. + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + trova_errori.download_excel_file( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + gridOptions = trova_errori.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)") + with expndr: + trova_errori.make_df_solo_errori() + + trova_errori.download_excel_file( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + gridOptions = trova_errori.buildGrid(trova_errori.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + + try: + trova_errori.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + + def genera_report(self) -> None: + """ + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + """ + try: + error_keys, errors_present = self._filter_errors(excluded_error="errMassimo543") + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + nr_bambini = self._compute_unique_children() + nr_comuni = self._compute_unique_gemeinden() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + excel_data = self._generate_excel_report(nr_bambini, nr_comuni, errors_present) + #pdf_data = self._generate_pdf_report(nr_bambini, nr_comuni, errors_present) + self._provide_downloads(excel_data) #, pdf_data) + st.success("Generato file riassunto analisi") + + except KeyError as ke: + st.error(f"Chiave mancante o struttura dati non valida: {ke}") + st.stop() + except ValueError as ve: + st.error(f"Problema di tipo o formato dati: {ve}") + st.stop() + except FileNotFoundError as fnf: + st.error(f"File di riferimento non trovato: {fnf}") + except PermissionError as pe: + st.error(f"Permessi insufficienti per accedere al file: {pe}") + except Exception as e: + st.error(f"Errore imprevisto durante la generazione del report: {e}") + st.stop() + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + + def _filter_errors(self, excluded_error: str): + """ + Excludes a specific error from the error dictionary and computes present errors. + + Returns: + Tuple[List[str], Dict[str, int]]: Filtered error keys and errors with counts > 0. + """ + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + if not error_keys: + return error_keys, {} + + error_counts = self.df[error_keys].sum() + errors_present = error_counts[error_counts > 0].to_dict() + #st.write(errors_present) + return error_keys, errors_present + + def _compute_unique_children(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Codice fiscale"].nunique() + + def _compute_unique_gemeinden(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Com_code"].nunique() + + def _generate_excel_report(self, nr_bambini: int, nr_comuni: int, errors_present: dict) -> bytes: + """ + Generates the Excel report and returns the binary data. + """ + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + self._write_excel_summary(worksheet, nr_bambini, nr_comuni, errors_present, workbook) + self._write_excel_detailed_sections(worksheet, errors_present, workbook) + return excel_buffer.getvalue() + + def _write_excel_summary(self, worksheet, nr_bambini: int, nr_comuni: int, errors_present: dict, workbook): + """ + Writes the summary section of the Excel report. + """ + #st.write(errors_present) + # Define formats + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + bold_format2 = workbook.add_format({'bold': True, 'font_size': 11}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 18}) + + # Initialize row and column + row, col = 3, 0 # Starting from row 1 as row 0 is typically reserved + + # Title + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + worksheet.set_row(row, 30) # Set row height to 30 + row += 4 + + # Number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini in {nr_comuni} comuni")#, bold_format) + row += 2 + + # Error counts + for error_key, count in errors_present.items(): + #st.write(error_key) + error_description = self.ERRORDICT.get(error_key, error_key) + #st.write(error_description) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}") #, bold_format) + row += 1 + row += 2 # Blank row + + # we extract the errors collected by caricaEtControlla and saved in the dictionary errori + + for key in processor.errori.keys(): + worksheet.write( + row, col, + f"Errori {key}:" + (" (file non usati)" if key == "critici" else ""), + bold_format + ) + row += 1 + for filename in processor.errori[key]: + worksheet.write( + row, col+1, + filename.split('/', 1)[1], + ) + + for error in processor.errori[key][filename]: + worksheet.write( + row, col+2, + error, + ) + row += 1 + row += 1 + row += 3 + + # Additional DataFrame + if not self.df_bambini.empty: + worksheet.write( + row, col, + "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", + bold_format + ) + row += 1 + + # Write column headers + for header_col, header in enumerate(self.df_bambini.columns): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths + worksheet.set_column(0, len(self.df_bambini.columns)-1, 25) + + # Write data rows + for _, r in self.df_bambini.iterrows(): + for header_col, header in enumerate(self.df_bambini.columns): + value = r.get(header, "") + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + row += 3 # Blank rows + + # Additional dataframe for the allegato 666 comparison + if not self.df_calcolo_666.empty: + + # Set fixed column widths + worksheet.set_column(0, len(self.df_calcolo_666.columns)-1, 25) + + # Write data rows + + filtered_df_ore = self.df_calcolo_666[self.df_calcolo_666['Confronto ore'] == False] + filtered_df_bambini = self.df_calcolo_666[self.df_calcolo_666['Confronto bambini'] == False] + + if not filtered_df_ore.empty: + #worksheet.write(row, col, "Incongruenza sul numero di ore", bold_format2) + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero delle ore per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Ore di servizio allegato 666", "Ore di assistenza report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_ore.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Ore di servizio allegato 666", "")) + worksheet.write(row, col + 3, r.get("Ore di assistenza report Comuni", "")) + row += 1 + row +=1 # Blank rows + + if not filtered_df_bambini.empty: + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero bambini per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Numero utenti allegato 666", "Numero bambini report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Numero utenti allegato 666", "")) + worksheet.write(row, col + 3, r.get("Numero bambini report Comuni", "")) + row += 1 + #row += 7 + + + def _write_excel_detailed_sections(self, worksheet, errors_present: dict, workbook): + """ + Writes detailed sections per error in the Excel report. + """ + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + date_format = workbook.add_format({'num_format': 'dd/mm/yyyy'}) + + row, col = worksheet.dim_rowmax, 0 + row += 4 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write(row, col, error_description, title_format2) + row += 2 + + # Changed headers for start and end contract dates + headers = [ + "Cognome", + "Nome", + "Codice fiscale", + "Data di nascita", + "Comune", + "Data inizio contratto", + "Data fine contratto", + ] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for header_col, header in enumerate(headers, start=1): + max_length = max( + self.df[header].astype(str).map(len).max() + if header in self.df.columns else 0, + len(header) + ) + 2 + worksheet.set_column(col + header_col, col + header_col, max_length + 5) + + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Nome", "")) + worksheet.write(row, col + 3, r.get("Codice fiscale", "")) + + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita) and isinstance(data_nascita, pd.Timestamp): + worksheet.write_datetime(row, col + 4, data_nascita, date_format) + else: + worksheet.write(row, col + 4, str(data_nascita)) + + worksheet.write(row, col + 5, r.get("Comune", "")) + + data_inizio = r.get("Data inizio contratto (o data inizio assistenza se diversa)", "") + if pd.notnull(data_inizio) and isinstance(data_inizio, pd.Timestamp): + worksheet.write_datetime(row, col + 6, data_inizio, date_format) + else: + worksheet.write(row, col + 6, str(data_inizio)) + + data_fine = r.get("Data fine contratto (o data fine assistenza se diversa)", "") + if pd.notnull(data_fine) and isinstance(data_fine, pd.Timestamp): + worksheet.write_datetime(row, col + 7, data_fine, date_format) + else: + worksheet.write(row, col + 7, str(data_fine)) + + row += 1 + row += 3 + + def _prepare_additional_df(self) -> pd.DataFrame: + """ + Prepares the additional DataFrame for the PDF report by renaming and dropping columns. + """ + additional_df = self.df_bambini.copy() + + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio Contratto' + column_list[4] = 'Data Fine Contratto' + # Assign back to additional_df.columns + additional_df.columns = column_list + # Position of the column to delete (e.g., 2 for the third column 'C') + position_to_delete = 5 + + position_to_delete = 5 # Adjust based on actual column index + if position_to_delete < len(additional_df.columns): + column_name = additional_df.columns[position_to_delete] + additional_df.drop(columns=column_name, inplace=True) + + return additional_df + + @st.fragment() + def _provide_downloads(self, excel_data: bytes): #, pdf_data: bytes): + """ + Provides download buttons for the generated Excel and PDF reports. + """ + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + #pdf_file_name = f"riassuntoAutomatico_{timestamp}.pdf" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report riassuntivo dell'analisi in formato Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Converts date columns in a DataFrame to string format. + Args: + df: A pandas DataFrame containing date columns to be converted. + + Returns: + df: The modified DataFrame with date columns formatted as strings. + """ + try: + # Convert 'Data di nascita' column + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + + # Convert 'Data fine contratto (o data fine assistenza se diversa)' column + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + + # Convert 'Data inizio contratto (o data inizio assistenza se diversa)' column + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Generates and displays a grid using the provided DataFrame. + + Args: + dff: A pandas DataFrame to be displayed in the grid. + k: A unique key for the component. + + Returns: + None + """ + + # Drop unnecessary columns from the DataFrame + dff = self.drop_columns(dff) + + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Builds and returns a GridOptions object from the given DataFrame. + Args: + data: A pandas DataFrame containing the data to be displayed in the grid. + Returns: + gridOptions: A GridOptions object configured with the specified data. + """ + + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Drops specified columns from the DataFrame. + Args: + df: A pandas DataFrame from which columns will be dropped. + + Returns: + df: The modified DataFrame with specified columns removed. + """ + + # Drop columns based on keys in ERRORDICT + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop() + + # Drop additional columns for specific year + if self.ANNO_RIFERIMENTO == "2020": + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + @st.fragment() + def download_excel_file( + self, + dftosave: pd.DataFrame, + nome_file: str, + flag: Optional[str] = None + ) -> None: + """ + Downloads an Excel file from the given DataFrame. + + Args: + dftosave (pd.DataFrame): A pandas DataFrame containing the data to be saved. + nome_file (str): The name of the file to save. + flag (Optional[str]): An optional flag to determine whether to drop columns with errors or not. + + Returns: + None + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop(columns=['Colonna_L_da_cancellare_dopo'], errors='ignore') + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f'{timestamp}_{nome_file}' + + # Step 3: Drop columns based on the flag + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def make_df_solo_errori(self) -> None: + """ + Creates a DataFrame containing only records with errors. + Returns: + None + """ + + self.dffinal: pd.DataFrame = self.df + # Create logical condition + # at least one error per error type + for e in self.ERRORDICT.keys(): + # do not want this column in the "error" df as there are too many of them + if e == "errMassimo543": + continue + # first instance of "condition" + # this way, it is created with the correct type + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione: pd.Series = self.dffinal[e] == True + else: + # simple solution: concatenate conditions for checks made + condizione: pd.Series = condizione | self.dffinal[e] == True + + # create df with only records with error + self.dffinal = self.dffinal[condizione] + + # pointless since we do not use this script for 2020 + if self.ANNO_RIFERIMENTO == "2020": + # drop the column we do not want + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error(f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error(f"La funzione {check} non è stata eseguita; errore generico: {e}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + #return self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, + na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors='coerce') + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & (actual_day != (giorno_nascita_code - 40)) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "H": 6, + "L": 7, "M": 8, "P": 9, "R": 10, "S": 11, "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, "G": 99, "I": 99, "J": 99, "K": 99, "N": 99, + "O": 99, "Q": 99, "U": 99, "V": 99, "W": 99, "X": 99, + "Y": 99, "Z": 99 + } + + mese_codice: pd.Series = cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + errors_mask: pd.Series = ( + day_mismatch_male | + day_mismatch_female | + month_mismatch | + year_mismatch + ) + + # Step 9: Check if any errors are found + if errors_mask.any(): + num_errori: int = errors_mask.sum() + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati." + ) + + # Step 10: Filter error records + results: pd.DataFrame = dfcod.loc[errors_mask].copy() + + # Step 11: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + # Step 12: Provide downloadable Excel file + self.download_excel_file( + results.sort_values(by=["Cognome", "Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + + # Step 13: Display the error data in an interactive grid within Streamlit + self.make_grid( + results.sort_values(by=["Cognome", "Nome"]), + "errCodFisc2x" + ) + + # Step 14: Flag the erroneous records in the main DataFrame + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + + def errCalcoloNumeroBimbi(self) -> None: + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ind] > 0: + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by='Com_code', ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on='Com_code', how='outer') + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[0, 8] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on='Com_code', how='outer') + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + 'Comune provenienza bambino', + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + 'PLZ', + 'Bezirk', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione' + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename(columns={ + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + }) + + # Step 12: Sort and rename columns based on the language code + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert(1, columns_order.pop(columns_order.index('Comune provenienza bambino'))) + columns_order.insert(2, columns_order.pop(columns_order.index('Numero utenti allegato 666'))) + columns_order.insert(3, columns_order.pop(columns_order.index('Numero bambini report Comuni'))) + columns_order.insert(4, columns_order.pop(columns_order.index('Ore di servizio allegato 666'))) + columns_order.insert(5, columns_order.pop(columns_order.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert(4, 'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7, 'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + 'Numero utenti allegato 666', + 'Numero bambini report Comuni', + 'Ore di servizio allegato 666', + 'Ore di assistenza report Comuni' + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = self.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + self.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "casospeciale" + ) + + # Display the DataFrame in an interactive grid + AgGrid( + dfx, + gridOptions=gridOptions, + enable_enterprise_modules=True + ) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[(dfx['Confronto bambini'] == False) | (dfx['Confronto ore'] == False)] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica: pd.Series = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(self.df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + condizione_logica: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errIncongruenzaDateAnnoRiferimento", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: + """ + Check if there are any records where the start date of the contract is after the end date. + """ + # Create a boolean condition for when the start date is greater than the end date + inizio_minore_fine: pd.Series = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + + # Combine this condition with NO_ZERO filter + condizione_logica: pd.Series = inizio_minore_fine & NO_ZERO + + # If there are any such records, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + + # Create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + # If required, convert date columns to string format + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + + # Set the flag for errors in the original dataframe + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: + """ + Check if the age of a child is less than 90 days. + Args: + None + Returns: + None + """ + + # Convert columns to datetime + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] = pd.to_datetime( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + ) + self.df["Data di nascita"] = pd.to_datetime(self.df["Data di nascita"]) + + # Then compute the difference + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + #st.write(giorni) + #st.write(self.df[giorni]) + + # Combine the condition with the NO_ZERO filter + condizione_logica: pd.Series = giorni & NO_ZERO + #st.write(self.df[condizione_logica]) + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_eta_bambino.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errAgeChildx", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errFineAssistenzaMax4Anni(self) -> None: + """ + Check if the end date of assistance is more than 4 years from the birthdate. + Args: + None + Returns: + None + """ + + # Calculate the number of days between the end date and the birthdate + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + # Combine the condition with the NO_ZERO filter + condizione_logica = giorni & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errFineAssistenzaMax4Annix", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten(self) -> None: + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Ensure necessary columns are present + required_columns = { + "Data di nascita", + "Data fine contratto (o data fine assistenza se diversa)", + "Cognome", + "Nome" + } + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError(f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'") + return + + # Convert relevant columns to datetime if not already + self.df["Data di nascita"] = pd.to_datetime( + self.df["Data di nascita"], format="%d.%m.%Y", errors='coerce' + ) + self.df["Data fine contratto (o data fine assistenza se diversa)"] = pd.to_datetime( + self.df["Data fine contratto (o data fine assistenza se diversa)"], format="%d.%m.%Y", errors='coerce' + ) + + # Define control date from constants + controllo_kinder_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + data_nascita: pd.Series = self.df["Data di nascita"] < controllo_kinder_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + birth_year_plus_3: pd.Series = self.df["Data di nascita"].dt.year + 3 + + # Create a Series of "04.09.{birth_year + 3}" as datetime + acceptable_end_date: pd.Series = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), format="%d.%m.%Y", errors='coerce' #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + ) + + # Compare "Data fine contratto..." with the acceptable end date + data_fine_ass: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > acceptable_end_date + + # Step 3: Apply additional condition if reference year is "2020" + if self.ANNO_RIFERIMENTO == "2020": + # Define an additional birth date condition + additional_birth_date_condition: pd.Series = self.df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y", errors='coerce' + ) + # Combine all conditions + condizione_logica: pd.Series = data_nascita & additional_birth_date_condition & data_fine_ass & NO_ZERO + else: + # Combine conditions without the additional birth date condition + condizione_logica: pd.Series = data_nascita & data_fine_ass & NO_ZERO + + # Step 4: Check if any errors are found + if condizione_logica.any(): + num_errori: int = condizione_logica.sum() + expndr = st.expander( + f"Trovato errore Kindergarten ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni" + ) + + # Filter the DataFrame for error records + dftemp: pd.DataFrame = self.df.loc[condizione_logica].copy() + + # Optional: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Provide a downloadable Excel file with sorted error records + dftemp_sorted = dftemp.sort_values(by=["Cognome", "Nome"]) + self.download_excel_file( + dftemp_sorted, + "errori_kindergarten.xlsx", + ) + + # Display the error records in an interactive grid within Streamlit + self.make_grid( + dftemp_sorted, + "errKindergartenx", + ) + + # Flag the erroneous records in the main DataFrame + erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + condizione_logica, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge( + df_multi, on="Codice fiscale", suffixes=("_1", "_2") + ) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform("sum").astype("float") + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + condizione_logica = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # Create an expandable section in Streamlit to display warnings and information + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errore/i)" + ) + with expndr: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + + # Convert date columns to strings if necessary + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + # Provide options to download the error data as an Excel file + self.download_excel_file( + dfx.sort_values(by=["Cognome", "Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + # Display the error data in a grid format + self.make_grid( + dfx.sort_values(by=["Cognome", "Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + def errSuperatoOreMassime1920(self) -> None: + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920." + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3a: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + # Step 3b: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errSuperatoOreMassime1920x", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + condizione_logica: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 3a: Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_in_piu_comuni.xlsx", + ) + + # Step 3c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errBambinoInPiuComunix", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizione & NO_ZERO + + # Step 3: Check if any records meet the combined condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errPresentiAnnotazionix", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + condizione_logica: pd.Series = ~condizione + + # Step 4: Check if any mismatches exist + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati {self.df[condizione_logica].shape[0]} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if ( + hasattr(interface, "CONVERTIDATESTRINGHE") + and interface.CONVERTIDATESTRINGHE + ): + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + #self.errori["critici"]["filename"] = [] + #self.errori["non critici"]["filename"] = [] + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + #self.errori["filename"] = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1,c2 = st.columns([3,2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append("Non ha il foglio con nome o ita o deu e non viene usato") + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non è un file Excel o non corrisponde alle aspettative") + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag ==2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + #c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error(f"Errore durante concatenamento dei dataframe caricati: errore: {e}") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + try: + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + except: + st.error(f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + except: + st.error(f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + + if codice_comune not in self.df_gemeinden["Com_code"].values: + #c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato codice comune non corretto") + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovati {somma} valori mancanti per le ore rendicontate") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri non progressivi") + + df_no_index = ( + df.loc[valid_progressivi & duplicates, ["Numero progressivo", "Cognome", "Nome"]] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index["Numero progressivo"].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Codice fiscale"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + #c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate.") + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = (df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna()) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovate righe con dati ma senza numero progressivo") + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato errore critico non identificato") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data fine contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data inizio contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + #c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split('-')[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df: pd.DataFrame, date_column: str, file) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError(f"The specified date_column '{date_column}' does not exist in the DataFrame.") + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + + #st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append(f"{date_column} contiene valori non data") + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + flag = 1 + #st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + #trova_errori = trovaErrori() + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + + #ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + trova_errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + #st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.zz" "b/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.zz" new file mode 100644 index 0000000000000000000000000000000000000000..461e55eedff4f45407e36b4d5c57fcfc40921c8e --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.6-VersioneNuova.py.zz" @@ -0,0 +1,2763 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +#from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +from io import BytesIO +from typing import Optional, List, Dict, Any +import re + +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import inch, cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.pdfgen import canvas +from reportlab.platypus import Image + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + ERRORDICT = {"2023": ERRORDICT2023} + + # Define a mapping from error keys to relevant emojis + ERROR_ICONS: Dict[str, str] = { + "errCodFisc1": "🧾", # Receipt + "errCodFisc2": "📅", # Calendar + "errAgeChild": "👶", # Baby + "errInizioMinoreFine": "🔄", # Repeat + "errFineAssistenzaMax4Anni": "⏳", # Hourglass + "errKindergarten": "🏫", # School + "errGesamtstundenVertragszeitraum": "⏰", # Alarm Clock + "errSuperatoOreMassime1920": "📊", # Bar Chart + "errBambinoInPiuComuni": "📍", # Location Pin + "errPresentiAnnotazioni": "📝", # Memo + "errOreRendicontateZero": "❌", # Cross Mark + "errCalcoloNumeroBimbi": "📋", # Clipboard + #"errNomeComuneTagesmutter": "🏠", # House + "errDateAnnoRiferimento": "📆", # Tear-Off Calendar + } + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.6)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + #self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + c1,c2 = st.columns(2) + self.choose_files(c1) + self.choose_allegato666(c2) + self.choose_checks() + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self, c1) -> None: + """Allow users to upload multiple Excel files for checking.""" + self.uploaded_files: List[FileUploadBase] = c1.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self, c2) -> None: + """ + Allow users to upload the Allegato 666 file for checking. + + Args: + None + + Returns: + None + """ + self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks" + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate(self.ERRORDICT.items()): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox" + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, 'TOLLERANZAZERO', False) or getattr(self, 'DEBUGWARNINGS', False): + st.error("Elaborazione interrotta") + st.stop() + + + def make_tabs(self) -> None: + """ + Creates tabs for the app. + + The tabs include 'INTEGRITÀ DATI', 'ERRORI e INCONGRUENZE RISCONTRATI', and 'TABELLE FINALI'. + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + +class ReportGenerator: + def __init__(self, processor, trova_errori, interface): + self.df = trova_errori.df + self.df_bambini = trova_errori.df_bambini_che_impediscono_controllo_superamento_ore + + self.df_calcolo_666 = trova_errori.df_calcolo_666 + self.dffinal = trova_errori.dffinal + + # st.write(self.df_calcolo_666) + + self.ERRORDICT = trova_errori.ERRORDICT + + @st.fragment() + def display_final_table(self) -> None: + """ + Displays the final table with all data and a separate table for errors only. + + This method creates two expanders: one for displaying all data in a grid format, + and another for showing only records that contain errors. It also provides options + to download these tables as Excel files. + + Args: + None + + Returns: + None + """ + no_zero = NO_ZERO # Assuming this is defined somewhere else in the code. + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + trova_errori.download_excel_file( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + gridOptions = trova_errori.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)") + with expndr: + trova_errori.make_df_solo_errori() + + trova_errori.download_excel_file( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + gridOptions = trova_errori.buildGrid(trova_errori.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + + try: + trova_errori.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + + def genera_report(self) -> None: + """ + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + """ + try: + error_keys, errors_present = self._filter_errors(excluded_error="errMassimo543") + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + nr_bambini = self._compute_unique_children() + nr_comuni = self._compute_unique_gemeinden() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + excel_data = self._generate_excel_report(nr_bambini, nr_comuni, errors_present) + #pdf_data = self._generate_pdf_report(nr_bambini, nr_comuni, errors_present) + self._provide_downloads(excel_data) #, pdf_data) + st.success("Generato file riassunto analisi") + + except KeyError as ke: + st.error(f"Chiave mancante o struttura dati non valida: {ke}") + st.stop() + except ValueError as ve: + st.error(f"Problema di tipo o formato dati: {ve}") + st.stop() + except FileNotFoundError as fnf: + st.error(f"File di riferimento non trovato: {fnf}") + except PermissionError as pe: + st.error(f"Permessi insufficienti per accedere al file: {pe}") + except Exception as e: + st.error(f"Errore imprevisto durante la generazione del report: {e}") + st.stop() + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + + def _filter_errors(self, excluded_error: str): + """ + Excludes a specific error from the error dictionary and computes present errors. + + Returns: + Tuple[List[str], Dict[str, int]]: Filtered error keys and errors with counts > 0. + """ + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + if not error_keys: + return error_keys, {} + + error_counts = self.df[error_keys].sum() + errors_present = error_counts[error_counts > 0].to_dict() + #st.write(errors_present) + return error_keys, errors_present + + def _compute_unique_children(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Codice fiscale"].nunique() + + def _compute_unique_gemeinden(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Com_code"].nunique() + + def _generate_excel_report(self, nr_bambini: int, nr_comuni: int, errors_present: dict) -> bytes: + """ + Generates the Excel report and returns the binary data. + """ + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + self._write_excel_summary(worksheet, nr_bambini, nr_comuni, errors_present, workbook) + self._write_excel_detailed_sections(worksheet, errors_present, workbook) + return excel_buffer.getvalue() + + def _write_excel_summary(self, worksheet, nr_bambini: int, nr_comuni: int, errors_present: dict, workbook): + """ + Writes the summary section of the Excel report. + """ + #st.write(errors_present) + # Define formats + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + bold_format2 = workbook.add_format({'bold': True, 'font_size': 11}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 18}) + + # Initialize row and column + row, col = 3, 0 # Starting from row 1 as row 0 is typically reserved + + # Title + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + worksheet.set_row(row, 30) # Set row height to 30 + row += 4 + + # Number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini in {nr_comuni} comuni")#, bold_format) + row += 2 + + # Error counts + for error_key, count in errors_present.items(): + #st.write(error_key) + error_description = self.ERRORDICT.get(error_key, error_key) + #st.write(error_description) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}") #, bold_format) + row += 1 + row += 2 # Blank row + + # we extract the errors collected by caricaEtControlla and saved in the dictionary errori + + for key in processor.errori.keys(): + worksheet.write( + row, col, + f"Errori {key}:" + (" (file non usati)" if key == "critici" else ""), + bold_format + ) + row += 1 + for filename in processor.errori[key]: + worksheet.write( + row, col+1, + filename.split('/', 1)[1], + ) + + for error in processor.errori[key][filename]: + worksheet.write( + row, col+2, + error, + ) + row += 1 + row += 1 + row += 3 + + # Additional DataFrame + if not self.df_bambini.empty: + worksheet.write( + row, col, + "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", + bold_format + ) + row += 1 + + # Write column headers + for header_col, header in enumerate(self.df_bambini.columns): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths + worksheet.set_column(0, len(self.df_bambini.columns)-1, 25) + + # Write data rows + for _, r in self.df_bambini.iterrows(): + for header_col, header in enumerate(self.df_bambini.columns): + value = r.get(header, "") + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + row += 3 # Blank rows + + # Additional dataframe for the allegato 666 comparison + if not self.df_calcolo_666.empty: + + # Set fixed column widths + worksheet.set_column(0, len(self.df_calcolo_666.columns)-1, 25) + + # Write data rows + + filtered_df_ore = self.df_calcolo_666[self.df_calcolo_666['Confronto ore'] == False] + filtered_df_bambini = self.df_calcolo_666[self.df_calcolo_666['Confronto bambini'] == False] + + if not filtered_df_ore.empty: + #worksheet.write(row, col, "Incongruenza sul numero di ore", bold_format2) + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero delle ore per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Ore di servizio allegato 666", "Ore di assistenza report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_ore.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Ore di servizio allegato 666", "")) + worksheet.write(row, col + 3, r.get("Ore di assistenza report Comuni", "")) + row += 1 + row +=1 # Blank rows + + if not filtered_df_bambini.empty: + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero bambini per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Numero utenti allegato 666", "Numero bambini report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Numero utenti allegato 666", "")) + worksheet.write(row, col + 3, r.get("Numero bambini report Comuni", "")) + row += 1 + #row += 7 + + + def _write_excel_detailed_sections(self, worksheet, errors_present: dict, workbook): + """ + Writes detailed sections per error in the Excel report. + """ + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + date_format = workbook.add_format({'num_format': 'dd/mm/yyyy'}) + + row, col = worksheet.dim_rowmax, 0 + row += 4 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write(row, col, error_description, title_format2) + row += 2 + + # Changed headers for start and end contract dates + headers = [ + "Cognome", + "Nome", + "Codice fiscale", + "Data di nascita", + "Comune", + "Data inizio contratto", + "Data fine contratto", + ] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for header_col, header in enumerate(headers, start=1): + max_length = max( + self.df[header].astype(str).map(len).max() + if header in self.df.columns else 0, + len(header) + ) + 2 + worksheet.set_column(col + header_col, col + header_col, max_length + 5) + + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Nome", "")) + worksheet.write(row, col + 3, r.get("Codice fiscale", "")) + + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita) and isinstance(data_nascita, pd.Timestamp): + worksheet.write_datetime(row, col + 4, data_nascita, date_format) + else: + worksheet.write(row, col + 4, str(data_nascita)) + + worksheet.write(row, col + 5, r.get("Comune", "")) + + data_inizio = r.get("Data inizio contratto (o data inizio assistenza se diversa)", "") + if pd.notnull(data_inizio) and isinstance(data_inizio, pd.Timestamp): + worksheet.write_datetime(row, col + 6, data_inizio, date_format) + else: + worksheet.write(row, col + 6, str(data_inizio)) + + data_fine = r.get("Data fine contratto (o data fine assistenza se diversa)", "") + if pd.notnull(data_fine) and isinstance(data_fine, pd.Timestamp): + worksheet.write_datetime(row, col + 7, data_fine, date_format) + else: + worksheet.write(row, col + 7, str(data_fine)) + + row += 1 + row += 3 + + def _prepare_additional_df(self) -> pd.DataFrame: + """ + Prepares the additional DataFrame for the PDF report by renaming and dropping columns. + """ + additional_df = self.df_bambini.copy() + + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio Contratto' + column_list[4] = 'Data Fine Contratto' + # Assign back to additional_df.columns + additional_df.columns = column_list + # Position of the column to delete (e.g., 2 for the third column 'C') + position_to_delete = 5 + + position_to_delete = 5 # Adjust based on actual column index + if position_to_delete < len(additional_df.columns): + column_name = additional_df.columns[position_to_delete] + additional_df.drop(columns=column_name, inplace=True) + + return additional_df + + @st.fragment() + def _provide_downloads(self, excel_data: bytes): #, pdf_data: bytes): + """ + Provides download buttons for the generated Excel and PDF reports. + """ + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + #pdf_file_name = f"riassuntoAutomatico_{timestamp}.pdf" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report riassuntivo dell'analisi in formato Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Converts date columns in a DataFrame to string format. + Args: + df: A pandas DataFrame containing date columns to be converted. + + Returns: + df: The modified DataFrame with date columns formatted as strings. + """ + try: + # Convert 'Data di nascita' column + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + + # Convert 'Data fine contratto (o data fine assistenza se diversa)' column + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + + # Convert 'Data inizio contratto (o data inizio assistenza se diversa)' column + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Generates and displays a grid using the provided DataFrame. + + Args: + dff: A pandas DataFrame to be displayed in the grid. + k: A unique key for the component. + + Returns: + None + """ + + # Drop unnecessary columns from the DataFrame + dff = self.drop_columns(dff) + + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Builds and returns a GridOptions object from the given DataFrame. + Args: + data: A pandas DataFrame containing the data to be displayed in the grid. + Returns: + gridOptions: A GridOptions object configured with the specified data. + """ + + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Drops specified columns from the DataFrame. + Args: + df: A pandas DataFrame from which columns will be dropped. + + Returns: + df: The modified DataFrame with specified columns removed. + """ + + # Drop columns based on keys in ERRORDICT + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop() + + # Drop additional columns for specific year + if self.ANNO_RIFERIMENTO == "2020": + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + @st.fragment() + def download_excel_file( + self, + dftosave: pd.DataFrame, + nome_file: str, + flag: Optional[str] = None + ) -> None: + """ + Downloads an Excel file from the given DataFrame. + + Args: + dftosave (pd.DataFrame): A pandas DataFrame containing the data to be saved. + nome_file (str): The name of the file to save. + flag (Optional[str]): An optional flag to determine whether to drop columns with errors or not. + + Returns: + None + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop(columns=['Colonna_L_da_cancellare_dopo'], errors='ignore') + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f'{timestamp}_{nome_file}' + + # Step 3: Drop columns based on the flag + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def make_df_solo_errori(self) -> None: + """ + Creates a DataFrame containing only records with errors. + Returns: + None + """ + + self.dffinal: pd.DataFrame = self.df + # Create logical condition + # at least one error per error type + for e in self.ERRORDICT.keys(): + # do not want this column in the "error" df as there are too many of them + if e == "errMassimo543": + continue + # first instance of "condition" + # this way, it is created with the correct type + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione: pd.Series = self.dffinal[e] == True + else: + # simple solution: concatenate conditions for checks made + condizione: pd.Series = condizione | self.dffinal[e] == True + + # create df with only records with error + self.dffinal = self.dffinal[condizione] + + # pointless since we do not use this script for 2020 + if self.ANNO_RIFERIMENTO == "2020": + # drop the column we do not want + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error(f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error(f"La funzione {check} non è stata eseguita; errore generico: {e}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + #return self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, + na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors='coerce') + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & (actual_day != (giorno_nascita_code - 40)) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "H": 6, + "L": 7, "M": 8, "P": 9, "R": 10, "S": 11, "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, "G": 99, "I": 99, "J": 99, "K": 99, "N": 99, + "O": 99, "Q": 99, "U": 99, "V": 99, "W": 99, "X": 99, + "Y": 99, "Z": 99 + } + + mese_codice: pd.Series = cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + errors_mask: pd.Series = ( + day_mismatch_male | + day_mismatch_female | + month_mismatch | + year_mismatch + ) + + # Step 9: Check if any errors are found + if errors_mask.any(): + num_errori: int = errors_mask.sum() + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati." + ) + + # Step 10: Filter error records + results: pd.DataFrame = dfcod.loc[errors_mask].copy() + + # Step 11: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + # Step 12: Provide downloadable Excel file + self.download_excel_file( + results.sort_values(by=["Cognome", "Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + + # Step 13: Display the error data in an interactive grid within Streamlit + self.make_grid( + results.sort_values(by=["Cognome", "Nome"]), + "errCodFisc2x" + ) + + # Step 14: Flag the erroneous records in the main DataFrame + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + + def errCalcoloNumeroBimbi(self) -> None: + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ind] > 0: + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by='Com_code', ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on='Com_code', how='outer') + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[0, 8] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on='Com_code', how='outer') + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + 'Comune provenienza bambino', + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + 'PLZ', + 'Bezirk', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione' + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename(columns={ + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + }) + + # Step 12: Sort and rename columns based on the language code + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert(1, columns_order.pop(columns_order.index('Comune provenienza bambino'))) + columns_order.insert(2, columns_order.pop(columns_order.index('Numero utenti allegato 666'))) + columns_order.insert(3, columns_order.pop(columns_order.index('Numero bambini report Comuni'))) + columns_order.insert(4, columns_order.pop(columns_order.index('Ore di servizio allegato 666'))) + columns_order.insert(5, columns_order.pop(columns_order.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert(4, 'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7, 'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + 'Numero utenti allegato 666', + 'Numero bambini report Comuni', + 'Ore di servizio allegato 666', + 'Ore di assistenza report Comuni' + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = self.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + self.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "casospeciale" + ) + + # Display the DataFrame in an interactive grid + AgGrid( + dfx, + gridOptions=gridOptions, + enable_enterprise_modules=True + ) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[(dfx['Confronto bambini'] == False) | (dfx['Confronto ore'] == False)] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica: pd.Series = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(self.df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + condizione_logica: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errIncongruenzaDateAnnoRiferimento", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: + """ + Check if there are any records where the start date of the contract is after the end date. + """ + # Create a boolean condition for when the start date is greater than the end date + inizio_minore_fine: pd.Series = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + + # Combine this condition with NO_ZERO filter + condizione_logica: pd.Series = inizio_minore_fine & NO_ZERO + + # If there are any such records, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + + # Create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + # If required, convert date columns to string format + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + + # Set the flag for errors in the original dataframe + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: + """ + Check if the age of a child is less than 90 days. + Args: + None + Returns: + None + """ + + # Convert columns to datetime + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] = pd.to_datetime( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + ) + self.df["Data di nascita"] = pd.to_datetime(self.df["Data di nascita"]) + + # Then compute the difference + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + #st.write(giorni) + #st.write(self.df[giorni]) + + # Combine the condition with the NO_ZERO filter + condizione_logica: pd.Series = giorni & NO_ZERO + #st.write(self.df[condizione_logica]) + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_eta_bambino.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errAgeChildx", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errFineAssistenzaMax4Anni(self) -> None: + """ + Check if the end date of assistance is more than 4 years from the birthdate. + Args: + None + Returns: + None + """ + + # Calculate the number of days between the end date and the birthdate + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + # Combine the condition with the NO_ZERO filter + condizione_logica = giorni & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errFineAssistenzaMax4Annix", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten(self) -> None: + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Ensure necessary columns are present + required_columns = { + "Data di nascita", + "Data fine contratto (o data fine assistenza se diversa)", + "Cognome", + "Nome" + } + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError(f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'") + return + + # Convert relevant columns to datetime if not already + self.df["Data di nascita"] = pd.to_datetime( + self.df["Data di nascita"], format="%d.%m.%Y", errors='coerce' + ) + self.df["Data fine contratto (o data fine assistenza se diversa)"] = pd.to_datetime( + self.df["Data fine contratto (o data fine assistenza se diversa)"], format="%d.%m.%Y", errors='coerce' + ) + + # Define control date from constants + controllo_kinder_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + data_nascita: pd.Series = self.df["Data di nascita"] < controllo_kinder_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + birth_year_plus_3: pd.Series = self.df["Data di nascita"].dt.year + 3 + + # Create a Series of "04.09.{birth_year + 3}" as datetime + acceptable_end_date: pd.Series = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), format="%d.%m.%Y", errors='coerce' #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + ) + + # Compare "Data fine contratto..." with the acceptable end date + data_fine_ass: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > acceptable_end_date + + # Step 3: Apply additional condition if reference year is "2020" + if self.ANNO_RIFERIMENTO == "2020": + # Define an additional birth date condition + additional_birth_date_condition: pd.Series = self.df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y", errors='coerce' + ) + # Combine all conditions + condizione_logica: pd.Series = data_nascita & additional_birth_date_condition & data_fine_ass & NO_ZERO + else: + # Combine conditions without the additional birth date condition + condizione_logica: pd.Series = data_nascita & data_fine_ass & NO_ZERO + + # Step 4: Check if any errors are found + if condizione_logica.any(): + num_errori: int = condizione_logica.sum() + expndr = st.expander( + f"Trovato errore Kindergarten ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni" + ) + + # Filter the DataFrame for error records + dftemp: pd.DataFrame = self.df.loc[condizione_logica].copy() + + # Optional: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Provide a downloadable Excel file with sorted error records + dftemp_sorted = dftemp.sort_values(by=["Cognome", "Nome"]) + self.download_excel_file( + dftemp_sorted, + "errori_kindergarten.xlsx", + ) + + # Display the error records in an interactive grid within Streamlit + self.make_grid( + dftemp_sorted, + "errKindergartenx", + ) + + # Flag the erroneous records in the main DataFrame + erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + condizione_logica, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge( + df_multi, on="Codice fiscale", suffixes=("_1", "_2") + ) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform("sum").astype("float") + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + condizione_logica = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # Create an expandable section in Streamlit to display warnings and information + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errore/i)" + ) + with expndr: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + + # Convert date columns to strings if necessary + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + # Provide options to download the error data as an Excel file + self.download_excel_file( + dfx.sort_values(by=["Cognome", "Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + # Display the error data in a grid format + self.make_grid( + dfx.sort_values(by=["Cognome", "Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + def errSuperatoOreMassime1920(self) -> None: + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920." + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3a: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + # Step 3b: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errSuperatoOreMassime1920x", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + condizione_logica: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 3a: Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_in_piu_comuni.xlsx", + ) + + # Step 3c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errBambinoInPiuComunix", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizione & NO_ZERO + + # Step 3: Check if any records meet the combined condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errPresentiAnnotazionix", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + condizione_logica: pd.Series = ~condizione + + # Step 4: Check if any mismatches exist + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati {self.df[condizione_logica].shape[0]} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if ( + hasattr(interface, "CONVERTIDATESTRINGHE") + and interface.CONVERTIDATESTRINGHE + ): + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + #self.errori["critici"]["filename"] = [] + #self.errori["non critici"]["filename"] = [] + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + #self.errori["filename"] = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1,c2 = st.columns([3,2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append("Non ha il foglio con nome o ita o deu e non viene usato") + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non è un file Excel o non corrisponde alle aspettative") + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag ==2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + #c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error(f"Errore durante concatenamento dei dataframe caricati: errore: {e}") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + try: + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + except: + st.error(f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + except: + st.error(f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + + if codice_comune not in self.df_gemeinden["Com_code"].values: + #c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato codice comune non corretto") + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovati {somma} valori mancanti per le ore rendicontate") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri non progressivi") + + df_no_index = ( + df.loc[valid_progressivi & duplicates, ["Numero progressivo", "Cognome", "Nome"]] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index["Numero progressivo"].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Codice fiscale"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + #c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate.") + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = (df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna()) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovate righe con dati ma senza numero progressivo") + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato errore critico non identificato") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data fine contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data inizio contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + #c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split('-')[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df: pd.DataFrame, date_column: str, file) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError(f"The specified date_column '{date_column}' does not exist in the DataFrame.") + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + + #st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append(f"{date_column} contiene valori non data") + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + flag = 1 + #st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + #trova_errori = trovaErrori() + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + + #ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + trova_errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + #st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.7.3-VersioneNuova.py.x" "b/pages/01_TagesMu\314\210tter_ver.3.7.3-VersioneNuova.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..202f8f684593d720adf949458adba02cded40331 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.7.3-VersioneNuova.py.x" @@ -0,0 +1,1864 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Controllo errori Tagesmütter (v. 3.7.3)") +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0, 5] + + try: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel( + "../commontools/GemeindenMitKodex.xlsx", dtype=dtype_spec + ) + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel("../commontools/TM_TraegerMitKodex.xlsx") + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.no" "b/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.no" new file mode 100644 index 0000000000000000000000000000000000000000..9be6df97f40976b1e9fa23be76e211adcde87e65 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.no" @@ -0,0 +1,1903 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import os + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# CONTROLLO ERRORI TAGESMUETTER") +st.markdown('## Roberta Bovo Special Edition 🤗 (ver. 4.0.5)') +st.write(f"{ReportGenerator.get_version(1)}, {helpers.get_version(1)}, {makeInterface.get_version(1)}") + +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + #st.write(f"codice_ente {df.iloc[2, 12]}") + codice_comune = df.iloc[4, 12] + #st.write(f"codice_comune {df.iloc[4, 12]}") + anno = df.iloc[0, 5] + + try: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + + # Get the directory where the script is located + # script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Build the full path to the Excel file + # file_path = os.path.join(script_dir, "GemeindenMitKodex.xlsx") + #st.write(file_path) + + # Read the file + try: + df_gemeinden = pd.read_excel("pages/GemeindenMitKodex.xlsx", dtype=dtype_spec) + #st.write(f"Columns 1: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + _df_gemeinden_backup = df_gemeinden.copy() + except Exception as e: + st.error(f"Primo; errore: {e}") + + try: + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + #st.write(f"Columns 2: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + if not isinstance(df_gemeinden, pd.DataFrame): + st.error("ATTENZIONE: df_gemeinden è stato sovrascritto — non è più un DataFrame!") + df_gemeinden = _df_gemeinden_backup.copy() + st.warning("df_gemeinden è stato ripristinato dalla copia di backup.") + except Exception as e: + st.write(df_gemeinden) + st.error(f"Secondo; errore: {e}") + #df_gemeinden = pd.read_excel( + # "GemeindenMitKodex.xlsx", dtype=dtype_spec + #) + #df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + #st.write(file_path) + #st.write(f"dtype_spec: {dtype_spec} ({type(dtype_spec)})") + + st.error(f"Errore durante caricamento file dei comuni; Errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + # Build the full path to the Excel file + file_path = os.path.join(script_dir, "TM_TraegerMitKodex.xlsx") + df_traeger = pd.read_excel(file_path, dtype=dtype_spec) + + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.previous" "b/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.previous" new file mode 100644 index 0000000000000000000000000000000000000000..9be6df97f40976b1e9fa23be76e211adcde87e65 --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.7.4-VersioneNuova.py.previous" @@ -0,0 +1,1903 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import os + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# CONTROLLO ERRORI TAGESMUETTER") +st.markdown('## Roberta Bovo Special Edition 🤗 (ver. 4.0.5)') +st.write(f"{ReportGenerator.get_version(1)}, {helpers.get_version(1)}, {makeInterface.get_version(1)}") + +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023","2024"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + #st.write(f"codice_ente {df.iloc[2, 12]}") + codice_comune = df.iloc[4, 12] + #st.write(f"codice_comune {df.iloc[4, 12]}") + anno = df.iloc[0, 5] + + try: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + + # Get the directory where the script is located + # script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Build the full path to the Excel file + # file_path = os.path.join(script_dir, "GemeindenMitKodex.xlsx") + #st.write(file_path) + + # Read the file + try: + df_gemeinden = pd.read_excel("pages/GemeindenMitKodex.xlsx", dtype=dtype_spec) + #st.write(f"Columns 1: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + _df_gemeinden_backup = df_gemeinden.copy() + except Exception as e: + st.error(f"Primo; errore: {e}") + + try: + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + #st.write(f"Columns 2: {df_gemeinden.columns} ({type(df_gemeinden.columns)})") + if not isinstance(df_gemeinden, pd.DataFrame): + st.error("ATTENZIONE: df_gemeinden è stato sovrascritto — non è più un DataFrame!") + df_gemeinden = _df_gemeinden_backup.copy() + st.warning("df_gemeinden è stato ripristinato dalla copia di backup.") + except Exception as e: + st.write(df_gemeinden) + st.error(f"Secondo; errore: {e}") + #df_gemeinden = pd.read_excel( + # "GemeindenMitKodex.xlsx", dtype=dtype_spec + #) + #df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + #st.write(file_path) + #st.write(f"dtype_spec: {dtype_spec} ({type(dtype_spec)})") + + st.error(f"Errore durante caricamento file dei comuni; Errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + # Build the full path to the Excel file + file_path = os.path.join(script_dir, "TM_TraegerMitKodex.xlsx") + df_traeger = pd.read_excel(file_path, dtype=dtype_spec) + + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.7.py.x" "b/pages/01_TagesMu\314\210tter_ver.3.7.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..c10e67dd4a5bdd2b67f7738ec9de72b756d5a2dc --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.7.py.x" @@ -0,0 +1,1864 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd + +pd.set_option("future.no_silent_downcasting", True) +import copy +import xlsxwriter +import streamlit as st + +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea + +# from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime + +from typing import Optional, List, Dict, Any +import re + +from utilities.interface import makeInterface +from utilities.helpertools_TM import helpers +from utilities.reportmaker import ReportGenerator +from utilities.valoriEtErrori import valoriEtErrori + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Controllo errori Tagesmütter (v. 3.7)") +# st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") # ffff + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + # let the show start + self.check_data() + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error( + f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error( + f"La funzione {check} non è stata eseguita; errore generico: {e}." + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: # refactored + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + cond_mask = codinvalido & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore formato del codice fiscale", + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[cond_mask, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: # refactored + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors="coerce") + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & ( + actual_day != (giorno_nascita_code - 40) + ) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, + "B": 2, + "C": 3, + "D": 4, + "E": 5, + "H": 6, + "L": 7, + "M": 8, + "P": 9, + "R": 10, + "S": 11, + "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, + "G": 99, + "I": 99, + "J": 99, + "K": 99, + "N": 99, + "O": 99, + "Q": 99, + "U": 99, + "V": 99, + "W": 99, + "X": 99, + "Y": 99, + "Z": 99, + } + + mese_codice: pd.Series = ( + cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + ) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + cond_mask: pd.Series = ( + day_mismatch_male | day_mismatch_female | month_mismatch | year_mismatch + ) + dob_col = "Data di nascita" + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + # Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + # Sort the dataframe and create a temporary dataframe for display + results: pd.DataFrame = dfcod.loc[cond_mask].copy() + + # Convert date columns to strings if required by the interface + results = helper.convert_dates_if_needed(results, []) + + # st.write(results) + interface.make_expander( + "errore data nascita per codice fiscale", + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati.", + num_errori, + results, + ) + + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errCalcoloNumeroBimbi(self) -> None: # not refactored + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ + ind + ] + > 0 + ): + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by="Com_code", ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on="Com_code", how="outer") + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[ + 0, 8 + ] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on="Com_code", how="outer") + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + "Comune provenienza bambino", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + "PLZ", + "Bezirk", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename( + columns={ + "Numero utenti": "Numero utenti allegato 666", + "Ore di servizio": "Ore di servizio allegato 666", + } + ) + + # Step 12: Sort and rename columns based on the language code + if lingua == "001": + dfx = dfx.sort_values(by="Comune") + dfx = dfx.rename(columns={"Comune": "Comune provenienza bambino"}) + dfx = dfx.drop("Gemeinde", axis=1) + elif lingua == "006": + dfx = dfx.sort_values(by="Gemeinde") + dfx = dfx.rename(columns={"Gemeinde": "Comune provenienza bambino"}) + dfx = dfx.drop("Comune", axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert( + 1, columns_order.pop(columns_order.index("Comune provenienza bambino")) + ) + columns_order.insert( + 2, columns_order.pop(columns_order.index("Numero utenti allegato 666")) + ) + columns_order.insert( + 3, + columns_order.pop(columns_order.index("Numero bambini report Comuni")), + ) + columns_order.insert( + 4, + columns_order.pop(columns_order.index("Ore di servizio allegato 666")), + ) + columns_order.insert( + 5, + columns_order.pop( + columns_order.index("Ore di assistenza report Comuni") + ), + ) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0).infer_objects(copy=False) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert( + 4, + "Confronto bambini", + dfx["Numero utenti allegato 666"] + == dfx["Numero bambini report Comuni"], + ) + dfx.insert( + 7, + "Confronto ore", + dfx["Ore di servizio allegato 666"] + == dfx["Ore di assistenza report Comuni"], + ) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + "Numero utenti allegato 666", + "Numero bambini report Comuni", + "Ore di servizio allegato 666", + "Ore di assistenza report Comuni", + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=["Somma"]) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc["Somma", col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = interface.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + interface.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "mantieniColonneErrore", + ) + + # Display the DataFrame in an interactive grid + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[ + (dfx["Confronto bambini"] == False) + | (dfx["Confronto ore"] == False) + ] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: # refactored + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con ore totali rendicontate uguali a zero", + "Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: # refactored + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + cond_mask: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + f"incongruenze data inizio o data fine in relazione all'anno di riferimento", + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento\n\r(data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: # refactored + """ + Check if start date > end date. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + if start_col not in self.df.columns or end_col not in self.df.columns: + return + + bad_mask = self.df[start_col] > self.df[end_col] + cond_mask = bad_mask & NO_ZERO + + if cond_mask.any(): + + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore date contrattuali", + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for errors in the original dataframe + self.df.loc[cond_mask, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: # refactored + """ + Check if the child is younger than 90 days at the start of the contract. + Sets 'errAgeChild' = True if discovered. + """ + start_col = "Data inizio contratto (o data inizio assistenza se diversa)" + dob_col = "Data di nascita" + if start_col not in self.df.columns or dob_col not in self.df.columns: + return + + # Convert to datetime + self.df[start_col] = pd.to_datetime(self.df[start_col], errors="coerce") + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + + age_mask = (self.df[start_col] - self.df[dob_col]).dt.days < 90 + cond_mask = age_mask & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore età bambino (< 90 giorni)", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi", + len(self.df[cond_mask]), + dftemp, + ) + + self.df.loc[cond_mask, "errAgeChild"] = True + + def errFineAssistenzaMax4Anni(self) -> None: # refactored + """ + End date must not exceed 4 years (1464 days) from birthdate. + """ + end_col = "Data fine contratto (o data fine assistenza se diversa)" + dob_col = "Data di nascita" + if end_col not in self.df.columns or dob_col not in self.df.columns: + return + + too_long = (self.df[end_col] - self.df[dob_col]).dt.days > 1464 + cond_mask = too_long & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore fine contratto assistenza", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: data fine contratto non può essere oltre 4 anni da data di nascita", + len(self.df[cond_mask]), + dftemp, + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[cond_mask, "errFineAssistenzaMax4Anni"] = True + + def errKindergarten(self) -> None: # refactored + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + If child's birth date < KONTROLLEKINDERGARTEN_DATANASCITA_2, + end date must not exceed a certain limit (04.09. of birth_year + 3). + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + dob_col = "Data di nascita" + end_col = "Data fine contratto (o data fine assistenza se diversa)" + # Ensure necessary columns are present + required_columns = {dob_col, end_col, "Cognome", "Nome"} + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError( + f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'" + ) + return + + # Convert + self.df[dob_col] = pd.to_datetime(self.df[dob_col], errors="coerce") + self.df[end_col] = pd.to_datetime(self.df[end_col], errors="coerce") + + # Define control date from constants + kontrolle_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + # Condition: child born before this date + older_kids = self.df[dob_col] < kontrolle_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + # Acceptable end date: 04.09.(birth_year + 3) + birth_year_plus_3 = self.df[dob_col].dt.year + 3 + + # Create date '04.09.YYYY' + acceptance_date = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), + format="%d.%m.%Y", + errors="coerce", + ) + + # Compare "Data fine contratto..." with the acceptable end date + bad_end_date = self.df[end_col] > acceptance_date + + cond_mask = older_kids & bad_end_date & NO_ZERO + + # Step 3: Check if any errors are found + if cond_mask.any(): + num_errori: int = cond_mask.sum() + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore Kindergarten", + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni", + num_errori, + dftemp, + ) + + # Flag the erroneous records in the main DataFrame + # erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + cond_mask, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: # not refactored + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")[ + "Comune" + ].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df["Codice fiscale"].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge(df_multi, on="Codice fiscale", suffixes=("_1", "_2")) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df[ + "Data inizio contratto (o data inizio assistenza se diversa)_2" + ] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform( + "sum" + ).astype( + "float" + ) + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + cond_mask = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if cond_mask.any(): + dfx = self.df[cond_mask].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # create a temporary dataframe for display + dftemp = dfx.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + # non usiamo la funzione perche' vogliamo la lista dei bimbi che impediscono il controllo nell'expander + with st.expander( + f"Trovate {len(dftemp)} occorrenze per errore Proportion Maximalstunden überschritten" + ): + if not self.df_bambini_che_impediscono_controllo_superamento_ore.empty: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(self.df_bambini_che_impediscono_controllo_superamento_ore) + + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + interface.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten", + ) + + interface.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errore Proportion Maximalstunden überschritten.xlsx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[cond_mask, "errGesamtstundenVertragszeitraum"] = True + + def errSuperatoOreMassime1920(self) -> None: # refactored + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "errore ore complessive maggiore di 1920", + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920.", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[cond_mask, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + cond_mask: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini presenti in più comuni", + "Elenco dei bambini trovati in più comuni (in più file Excel)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[cond_mask, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: # refactored + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + cond_mask: pd.Series = condizione & NO_ZERO + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "bambini con annotazioni", + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[cond_mask, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: # refactored + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + cond_mask: pd.Series = ~condizione + + if cond_mask.any(): + # create a temporary dataframe for display + dftemp = self.df.loc[cond_mask].copy() + + dftemp = helper.convert_dates_if_needed(dftemp, []) + + interface.make_expander( + "casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale", + "Elenco delle occorrenze con comune Tagesmutter non corrispondente", + len(dftemp[cond_mask]), + dftemp, + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1, c2 = st.columns([3, 2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append( + "Non ha il foglio con nome o ita o deu e non viene usato" + ) + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Non è un file Excel o non corrisponde alle aspettative" + ) + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag == 2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + # st.write(df) + self.dataframes.append(df) + # st.write(df) + # c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error( + f"Errore durante concatenamento dei dataframe caricati: errore: {e}" + ) + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + # st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2, 12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0, 5] + + try: + nome_comune = df_gemeinden[df_gemeinden["Com_code"] == codice_comune][ + "Comune" + ].values[0] + except: + st.error( + f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger["Coop_code"] == codice_ente][ + "Körperschaft" + ].values[0] + except: + st.error( + f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + if codice_comune not in self.df_gemeinden["Com_code"].values: + # c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato codice comune non corretto" + ) + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1, "Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = ( + df["Ore di assistenza ai sensi della delibera n. 666/2019"] + .isnull() + .sum() + ) + c2.warning("Attenzione!") + st.error( + f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovati {somma} valori mancanti per le ore rendicontate" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri non progressivi" + ) + + df_no_index = ( + df.loc[ + valid_progressivi & duplicates, + ["Numero progressivo", "Cognome", "Nome"], + ] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index[ + "Numero progressivo" + ].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = ( + ~df["Numero progressivo"].isna() & df["Codice fiscale"].isna() + ) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + # c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate." + ) + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = ( + df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna() + ) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append( + "Trovate righe con dati ma senza numero progressivo" + ) + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime( + int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0 + ) # str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df, "Data di nascita", file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error( + f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Trovato errore critico non identificato" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data fine contratto (o data fine assistenza se diversa)", file + ) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data fine contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates( + df, "Data inizio contratto (o data inizio assistenza se diversa)", file + ) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error( + f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + "Data inizio contratto contiene valori non data" + ) + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if "Colonna_L_da_cancellare_dopo" in df.columns: + del df["Colonna_L_da_cancellare_dopo"] + + # c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split("-")[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates( + self, df: pd.DataFrame, date_column: str, file + ) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError( + f"The specified date_column '{date_column}' does not exist in the DataFrame." + ) + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime( + df[date_column], format="%d-%m-%Y", errors="coerce" + ) # .dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error( + f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato" + ) + + # st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append( + f"{date_column} contiene valori non data" + ) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop("Parsed Date", axis=1, inplace=True) + flag = 1 + # st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop("Parsed Date", axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df["Data fine contratto (o data fine assistenza se diversa)"] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + + # df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = ( + total_effective_days + 1 + ) + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + + +if __name__ == "__main__": + + valori = valoriEtErrori() + interface = makeInterface(valori) + helper = helpers(interface, valori.ERRORDICT) + # trova_errori = trovaErrori() + + dtype_spec = { + "Com_code": str # non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel( + "../commontools/GemeindenMitKodex.xlsx", dtype=dtype_spec + ) + df_gemeinden = df_gemeinden[df_gemeinden["PLZ"] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel("../commontools/TM_TraegerMitKodex.xlsx") + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666.columns[24] != 666: + st.error( + f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata." + ) + st.stop() + df_allegato666 = df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 = df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns="Unnamed: 8") + + # ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + "Comune provenienza bambino", + "Numero utenti", + "Ore di servizio", + "Costo orario", + "Costo del servizio", + "Entrate compartecipazione", + "Ore tariffa maggiorata", + "Entrate maggiorazione", + "Com_code", + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error( + f"Errore durante il caricamento dell'allegato 666: errore: {e}" + ) + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla( + interface, valori.ERRORDICT, df_gemeinden, df_traeger + ) + processor.process_data() + + trova_errori = trovaErrori( + processor.get_data(), interface, df_gemeinden, df_allegato666 + ) + # st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + # st.balloons() diff --git "a/pages/01_TagesMu\314\210tter_ver.3.71.py.x" "b/pages/01_TagesMu\314\210tter_ver.3.71.py.x" new file mode 100644 index 0000000000000000000000000000000000000000..461e55eedff4f45407e36b4d5c57fcfc40921c8e --- /dev/null +++ "b/pages/01_TagesMu\314\210tter_ver.3.71.py.x" @@ -0,0 +1,2763 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +#from streamlit.uploaded_file_manager import UploadedFile as FileUploadBase +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +from io import BytesIO +from typing import Optional, List, Dict, Any +import re + +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import inch, cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.pdfgen import canvas +from reportlab.platypus import Image + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + ERRORDICT = {"2023": ERRORDICT2023} + + # Define a mapping from error keys to relevant emojis + ERROR_ICONS: Dict[str, str] = { + "errCodFisc1": "🧾", # Receipt + "errCodFisc2": "📅", # Calendar + "errAgeChild": "👶", # Baby + "errInizioMinoreFine": "🔄", # Repeat + "errFineAssistenzaMax4Anni": "⏳", # Hourglass + "errKindergarten": "🏫", # School + "errGesamtstundenVertragszeitraum": "⏰", # Alarm Clock + "errSuperatoOreMassime1920": "📊", # Bar Chart + "errBambinoInPiuComuni": "📍", # Location Pin + "errPresentiAnnotazioni": "📝", # Memo + "errOreRendicontateZero": "❌", # Cross Mark + "errCalcoloNumeroBimbi": "📋", # Clipboard + #"errNomeComuneTagesmutter": "🏠", # House + "errDateAnnoRiferimento": "📆", # Tear-Off Calendar + } + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 3.6)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023"]), index=0 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + #self.MOSTRACOLONNEERRORE = st.sidebar.checkbox("Includi colonne errore nei file finali", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + c1,c2 = st.columns(2) + self.choose_files(c1) + self.choose_allegato666(c2) + self.choose_checks() + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self, c1) -> None: + """Allow users to upload multiple Excel files for checking.""" + self.uploaded_files: List[FileUploadBase] = c1.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_allegato666(self, c2) -> None: + """ + Allow users to upload the Allegato 666 file for checking. + + Args: + None + + Returns: + None + """ + self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + "CARICARE ALLEGATO 666", accept_multiple_files=False + ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks" + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate(self.ERRORDICT.items()): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox" + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, 'TOLLERANZAZERO', False) or getattr(self, 'DEBUGWARNINGS', False): + st.error("Elaborazione interrotta") + st.stop() + + + def make_tabs(self) -> None: + """ + Creates tabs for the app. + + The tabs include 'INTEGRITÀ DATI', 'ERRORI e INCONGRUENZE RISCONTRATI', and 'TABELLE FINALI'. + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + +class ReportGenerator: + def __init__(self, processor, trova_errori, interface): + self.df = trova_errori.df + self.df_bambini = trova_errori.df_bambini_che_impediscono_controllo_superamento_ore + + self.df_calcolo_666 = trova_errori.df_calcolo_666 + self.dffinal = trova_errori.dffinal + + # st.write(self.df_calcolo_666) + + self.ERRORDICT = trova_errori.ERRORDICT + + @st.fragment() + def display_final_table(self) -> None: + """ + Displays the final table with all data and a separate table for errors only. + + This method creates two expanders: one for displaying all data in a grid format, + and another for showing only records that contain errors. It also provides options + to download these tables as Excel files. + + Args: + None + + Returns: + None + """ + no_zero = NO_ZERO # Assuming this is defined somewhere else in the code. + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + trova_errori.download_excel_file( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + gridOptions = trova_errori.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)") + with expndr: + trova_errori.make_df_solo_errori() + + trova_errori.download_excel_file( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + gridOptions = trova_errori.buildGrid(trova_errori.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + trova_errori.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + + try: + trova_errori.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + + def genera_report(self) -> None: + """ + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + """ + try: + error_keys, errors_present = self._filter_errors(excluded_error="errMassimo543") + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + nr_bambini = self._compute_unique_children() + nr_comuni = self._compute_unique_gemeinden() + + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + excel_data = self._generate_excel_report(nr_bambini, nr_comuni, errors_present) + #pdf_data = self._generate_pdf_report(nr_bambini, nr_comuni, errors_present) + self._provide_downloads(excel_data) #, pdf_data) + st.success("Generato file riassunto analisi") + + except KeyError as ke: + st.error(f"Chiave mancante o struttura dati non valida: {ke}") + st.stop() + except ValueError as ve: + st.error(f"Problema di tipo o formato dati: {ve}") + st.stop() + except FileNotFoundError as fnf: + st.error(f"File di riferimento non trovato: {fnf}") + except PermissionError as pe: + st.error(f"Permessi insufficienti per accedere al file: {pe}") + except Exception as e: + st.error(f"Errore imprevisto durante la generazione del report: {e}") + st.stop() + # Optionally log the error + # self.logger.error(f"Errore durante la generazione del report: {e}") + + def _filter_errors(self, excluded_error: str): + """ + Excludes a specific error from the error dictionary and computes present errors. + + Returns: + Tuple[List[str], Dict[str, int]]: Filtered error keys and errors with counts > 0. + """ + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + if not error_keys: + return error_keys, {} + + error_counts = self.df[error_keys].sum() + errors_present = error_counts[error_counts > 0].to_dict() + #st.write(errors_present) + return error_keys, errors_present + + def _compute_unique_children(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Codice fiscale"].nunique() + + def _compute_unique_gemeinden(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + """ + return self.df["Com_code"].nunique() + + def _generate_excel_report(self, nr_bambini: int, nr_comuni: int, errors_present: dict) -> bytes: + """ + Generates the Excel report and returns the binary data. + """ + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + self._write_excel_summary(worksheet, nr_bambini, nr_comuni, errors_present, workbook) + self._write_excel_detailed_sections(worksheet, errors_present, workbook) + return excel_buffer.getvalue() + + def _write_excel_summary(self, worksheet, nr_bambini: int, nr_comuni: int, errors_present: dict, workbook): + """ + Writes the summary section of the Excel report. + """ + #st.write(errors_present) + # Define formats + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + bold_format2 = workbook.add_format({'bold': True, 'font_size': 11}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 18}) + + # Initialize row and column + row, col = 3, 0 # Starting from row 1 as row 0 is typically reserved + + # Title + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + worksheet.set_row(row, 30) # Set row height to 30 + row += 4 + + # Number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini in {nr_comuni} comuni")#, bold_format) + row += 2 + + # Error counts + for error_key, count in errors_present.items(): + #st.write(error_key) + error_description = self.ERRORDICT.get(error_key, error_key) + #st.write(error_description) + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}") #, bold_format) + row += 1 + row += 2 # Blank row + + # we extract the errors collected by caricaEtControlla and saved in the dictionary errori + + for key in processor.errori.keys(): + worksheet.write( + row, col, + f"Errori {key}:" + (" (file non usati)" if key == "critici" else ""), + bold_format + ) + row += 1 + for filename in processor.errori[key]: + worksheet.write( + row, col+1, + filename.split('/', 1)[1], + ) + + for error in processor.errori[key][filename]: + worksheet.write( + row, col+2, + error, + ) + row += 1 + row += 1 + row += 3 + + # Additional DataFrame + if not self.df_bambini.empty: + worksheet.write( + row, col, + "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", + bold_format + ) + row += 1 + + # Write column headers + for header_col, header in enumerate(self.df_bambini.columns): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths + worksheet.set_column(0, len(self.df_bambini.columns)-1, 25) + + # Write data rows + for _, r in self.df_bambini.iterrows(): + for header_col, header in enumerate(self.df_bambini.columns): + value = r.get(header, "") + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + row += 3 # Blank rows + + # Additional dataframe for the allegato 666 comparison + if not self.df_calcolo_666.empty: + + # Set fixed column widths + worksheet.set_column(0, len(self.df_calcolo_666.columns)-1, 25) + + # Write data rows + + filtered_df_ore = self.df_calcolo_666[self.df_calcolo_666['Confronto ore'] == False] + filtered_df_bambini = self.df_calcolo_666[self.df_calcolo_666['Confronto bambini'] == False] + + if not filtered_df_ore.empty: + #worksheet.write(row, col, "Incongruenza sul numero di ore", bold_format2) + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero delle ore per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Ore di servizio allegato 666", "Ore di assistenza report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_ore.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Ore di servizio allegato 666", "")) + worksheet.write(row, col + 3, r.get("Ore di assistenza report Comuni", "")) + row += 1 + row +=1 # Blank rows + + if not filtered_df_bambini.empty: + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero bambini per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Numero utenti allegato 666", "Numero bambini report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Numero utenti allegato 666", "")) + worksheet.write(row, col + 3, r.get("Numero bambini report Comuni", "")) + row += 1 + #row += 7 + + + def _write_excel_detailed_sections(self, worksheet, errors_present: dict, workbook): + """ + Writes detailed sections per error in the Excel report. + """ + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + date_format = workbook.add_format({'num_format': 'dd/mm/yyyy'}) + + row, col = worksheet.dim_rowmax, 0 + row += 4 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write(row, col, error_description, title_format2) + row += 2 + + # Changed headers for start and end contract dates + headers = [ + "Cognome", + "Nome", + "Codice fiscale", + "Data di nascita", + "Comune", + "Data inizio contratto", + "Data fine contratto", + ] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for header_col, header in enumerate(headers, start=1): + max_length = max( + self.df[header].astype(str).map(len).max() + if header in self.df.columns else 0, + len(header) + ) + 2 + worksheet.set_column(col + header_col, col + header_col, max_length + 5) + + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Nome", "")) + worksheet.write(row, col + 3, r.get("Codice fiscale", "")) + + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita) and isinstance(data_nascita, pd.Timestamp): + worksheet.write_datetime(row, col + 4, data_nascita, date_format) + else: + worksheet.write(row, col + 4, str(data_nascita)) + + worksheet.write(row, col + 5, r.get("Comune", "")) + + data_inizio = r.get("Data inizio contratto (o data inizio assistenza se diversa)", "") + if pd.notnull(data_inizio) and isinstance(data_inizio, pd.Timestamp): + worksheet.write_datetime(row, col + 6, data_inizio, date_format) + else: + worksheet.write(row, col + 6, str(data_inizio)) + + data_fine = r.get("Data fine contratto (o data fine assistenza se diversa)", "") + if pd.notnull(data_fine) and isinstance(data_fine, pd.Timestamp): + worksheet.write_datetime(row, col + 7, data_fine, date_format) + else: + worksheet.write(row, col + 7, str(data_fine)) + + row += 1 + row += 3 + + def _prepare_additional_df(self) -> pd.DataFrame: + """ + Prepares the additional DataFrame for the PDF report by renaming and dropping columns. + """ + additional_df = self.df_bambini.copy() + + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio Contratto' + column_list[4] = 'Data Fine Contratto' + # Assign back to additional_df.columns + additional_df.columns = column_list + # Position of the column to delete (e.g., 2 for the third column 'C') + position_to_delete = 5 + + position_to_delete = 5 # Adjust based on actual column index + if position_to_delete < len(additional_df.columns): + column_name = additional_df.columns[position_to_delete] + additional_df.drop(columns=column_name, inplace=True) + + return additional_df + + @st.fragment() + def _provide_downloads(self, excel_data: bytes): #, pdf_data: bytes): + """ + Provides download buttons for the generated Excel and PDF reports. + """ + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + #pdf_file_name = f"riassuntoAutomatico_{timestamp}.pdf" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report riassuntivo dell'analisi in formato Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) + + +class trovaErrori: + def __init__(self, df, interface, df_gemeinden, df_allegato666): + self.checks = interface.checks + self.df_allegato666 = df_allegato666 + self.uploaded_allegato666 = interface.uploaded_allegato666 + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df_gemeinden = df_gemeinden + self.df = df + self.dffinal = pd.DataFrame + self.df_bambini_che_impediscono_controllo_superamento_ore = pd.DataFrame + + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Converts date columns in a DataFrame to string format. + Args: + df: A pandas DataFrame containing date columns to be converted. + + Returns: + df: The modified DataFrame with date columns formatted as strings. + """ + try: + # Convert 'Data di nascita' column + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + + # Convert 'Data fine contratto (o data fine assistenza se diversa)' column + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + + # Convert 'Data inizio contratto (o data inizio assistenza se diversa)' column + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Generates and displays a grid using the provided DataFrame. + + Args: + dff: A pandas DataFrame to be displayed in the grid. + k: A unique key for the component. + + Returns: + None + """ + + # Drop unnecessary columns from the DataFrame + dff = self.drop_columns(dff) + + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Builds and returns a GridOptions object from the given DataFrame. + Args: + data: A pandas DataFrame containing the data to be displayed in the grid. + Returns: + gridOptions: A GridOptions object configured with the specified data. + """ + + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Drops specified columns from the DataFrame. + Args: + df: A pandas DataFrame from which columns will be dropped. + + Returns: + df: The modified DataFrame with specified columns removed. + """ + + # Drop columns based on keys in ERRORDICT + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop() + + # Drop additional columns for specific year + if self.ANNO_RIFERIMENTO == "2020": + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + @st.fragment() + def download_excel_file( + self, + dftosave: pd.DataFrame, + nome_file: str, + flag: Optional[str] = None + ) -> None: + """ + Downloads an Excel file from the given DataFrame. + + Args: + dftosave (pd.DataFrame): A pandas DataFrame containing the data to be saved. + nome_file (str): The name of the file to save. + flag (Optional[str]): An optional flag to determine whether to drop columns with errors or not. + + Returns: + None + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop(columns=['Colonna_L_da_cancellare_dopo'], errors='ignore') + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f'{timestamp}_{nome_file}' + + # Step 3: Drop columns based on the flag + if flag == 'mantieniColonneErrore': + pass + else: + dftosave = self.drop_columns(dftosave) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def make_df_solo_errori(self) -> None: + """ + Creates a DataFrame containing only records with errors. + Returns: + None + """ + + self.dffinal: pd.DataFrame = self.df + # Create logical condition + # at least one error per error type + for e in self.ERRORDICT.keys(): + # do not want this column in the "error" df as there are too many of them + if e == "errMassimo543": + continue + # first instance of "condition" + # this way, it is created with the correct type + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione: pd.Series = self.dffinal[e] == True + else: + # simple solution: concatenate conditions for checks made + condizione: pd.Series = condizione | self.dffinal[e] == True + + # create df with only records with error + self.dffinal = self.dffinal[condizione] + + # pointless since we do not use this script for 2020 + if self.ANNO_RIFERIMENTO == "2020": + # drop the column we do not want + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + + def check_data(self) -> None: + """ + Checks the data for errors and performs necessary operations. + + This method iterates through the selected checks, calls the corresponding error checking methods, + and updates the status of the checks. + """ + global NO_ZERO + column_name = "Ore di assistenza ai sensi della delibera n. 666/2019" + NO_ZERO = self.df[column_name].astype("float") > 0 + + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + try: + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + getattr(self, check)() + except AttributeError as ae: + st.error(f"La funzione {check} non esiste; errore: {ae}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except TypeError as te: + st.error(f"Il metodo {check} ha problemi con i tipi di dati; errore: {te}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + except Exception as e: + st.error(f"La funzione {check} non è stata eseguita; errore generico: {e}.") + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + #return self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self) -> None: + """ + Controlla la validità del codice fiscale. + + Questa funzione rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale, + quindi controlla se il formato è corretto utilizzando una regex. Se un codice fiscale + non è valido, viene segnalato ed aggiunto a una tabella temporanea. + """ + + # rimuove eventuali spazi bianchi all'inizio e alla fine del codice fiscale + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + def errCodFisc2(self) -> None: + """ + Validates the correctness of the "Codice fiscale" (fiscal code) for each child in the DataFrame. + + This method performs the following operations: + 1. Validates the format of the "Codice fiscale" using a regular expression. + 2. Filters records with valid "Codice fiscale". + 3. Determines gender based on the "Codice fiscale" and validates the day of birth. + 4. Validates the month of birth encoded in the "Codice fiscale" against the actual birth date. + 5. Validates that the year of birth encoded in the "Codice fiscale" matches the actual birth date. + 6. Aggregates and identifies records with inconsistencies. + 7. Displays the errors in an expandable section within Streamlit. + 8. Provides options to download the error data and displays it in an interactive grid. + 9. Flags the erroneous records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Step 1: Precompile the regex pattern for performance + codice_fiscale_pattern: re.Pattern = re.compile( + r"^[A-Za-z]{6}\d{2}[A-Za-z]\d{2}[A-Za-z]\d{3}[A-Za-z]$" + ) + + # Step 2: Validate the format of "Codice fiscale" using the compiled regex + codvalido: pd.Series = self.df["Codice fiscale"].str.match( + codice_fiscale_pattern, + na=False # Treat NaN as non-matching + ) + + # Step 3: Filter records with valid "Codice fiscale" + dfcod: pd.DataFrame = self.df.loc[codvalido].copy() + + # Ensure required columns are present + required_columns = {"Codice fiscale", "Data di nascita", "Cognome", "Nome"} + if not required_columns.issubset(dfcod.columns): + missing = required_columns - set(dfcod.columns) + raise KeyError(f"Colonne mancanti: {missing}") + + # Step 4: Extract components from "Codice fiscale" + cf = dfcod["Codice fiscale"] + + # Extract and convert day code + giorno_nascita_code: pd.Series = cf.str[9:11].astype(int) + + # Determine gender based on day code + is_male: pd.Series = giorno_nascita_code < 40 + is_female: pd.Series = giorno_nascita_code >= 40 + + # Extract actual day from "Data di nascita" + data_nascita = pd.to_datetime(dfcod["Data di nascita"], errors='coerce') + actual_day: pd.Series = data_nascita.dt.day + actual_month: pd.Series = data_nascita.dt.month + actual_year: pd.Series = data_nascita.dt.year + + # Step 5: Validate day of birth + day_mismatch_male: pd.Series = is_male & (actual_day != giorno_nascita_code) + day_mismatch_female: pd.Series = is_female & (actual_day != (giorno_nascita_code - 40)) + + # Step 6: Validate year of birth + year_code: pd.Series = 2000 + cf.str[6:8].astype(int) + year_mismatch: pd.Series = actual_year != year_code + + # Step 7: Validate month of birth + mese_mapping: Dict[str, int] = { + "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "H": 6, + "L": 7, "M": 8, "P": 9, "R": 10, "S": 11, "T": 12, + # Invalid or unused letters mapped to 99 + "F": 99, "G": 99, "I": 99, "J": 99, "K": 99, "N": 99, + "O": 99, "Q": 99, "U": 99, "V": 99, "W": 99, "X": 99, + "Y": 99, "Z": 99 + } + + mese_codice: pd.Series = cf.str[8].str.upper().map(mese_mapping).fillna(99).astype(int) + month_mismatch: pd.Series = actual_month != mese_codice + + # Step 8: Aggregate all mismatches + errors_mask: pd.Series = ( + day_mismatch_male | + day_mismatch_female | + month_mismatch | + year_mismatch + ) + + # Step 9: Check if any errors are found + if errors_mask.any(): + num_errori: int = errors_mask.sum() + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale.\nATTENZIONE: il bambino potrebbe apparire più volte, a seconda di quanti errori vengono trovati." + ) + + # Step 10: Filter error records + results: pd.DataFrame = dfcod.loc[errors_mask].copy() + + # Step 11: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + # Step 12: Provide downloadable Excel file + self.download_excel_file( + results.sort_values(by=["Cognome", "Nome"]), + "errore_codice_fiscale_2.xlsx", + ) + + # Step 13: Display the error data in an interactive grid within Streamlit + self.make_grid( + results.sort_values(by=["Cognome", "Nome"]), + "errCodFisc2x" + ) + + # Step 14: Flag the erroneous records in the main DataFrame + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + + def errCalcoloNumeroBimbi(self) -> None: + """ + Identifies and processes errors related to the calculation of the number of children + and their corresponding assistance hours for the reference year. + + This method performs the following operations: + 1. Resets the index of the main DataFrame. + 2. Filters records for the reference year (2023). + 3. Creates a DataFrame (`df666`) excluding duplicate tax codes ("Codice fiscale") + while ensuring that the assistance hours are greater than zero. + 4. Aggregates data to calculate the sum of assistance days and counts of children per municipality. + 5. Merges aggregated data to form a consolidated DataFrame (`dfx`). + 6. Merges with additional datasets (`df_gemeinden` and `df_allegato666`) for comprehensive analysis. + 7. Cleans and formats the consolidated DataFrame. + 8. Inserts comparison columns to verify consistency between different data sources. + 9. Calculates and appends summary rows to the DataFrame. + 10. Displays the final table in an expandable section within Streamlit and provides download options. + + Raises: + KeyError: If expected columns are missing from `self.df`, `df_gemeinden`, or `df_allegato666`. + Exception: For any other exceptions that occur during DataFrame operations. + """ + # Step 1: Reset the index of the main DataFrame to ensure it's clean + self.df = self.df.reset_index(drop=True) + + # Step 2: Proceed only if the reference year is 2023 + if self.ANNO_RIFERIMENTO in ["2023"]: + # Initialize an empty DataFrame `df666` with specified columns + df666: pd.DataFrame = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza ai sensi della delibera n. 666/2019", + ] + ) + + # Iterate through each record to populate `df666` + for ind in self.df.index: + # Check if the assistance hours are greater than zero + if self.df["Ore di assistenza ai sensi della delibera n. 666/2019"][ind] > 0: + if df666.empty: + # If `df666` is empty, add the current record + df666 = self.df.loc[[ind]] + else: + # Check for duplicate "Codice fiscale" and "Com_code" to avoid duplicates + is_duplicate: bool = ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Com_code"][ind] == df666["Com_code"]) + ).any() + if not is_duplicate: + # Concatenate the current record if it's not a duplicate + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue # Skip duplicate records + + # Step 3: Aggregate the sum of assistance days per municipality + df1: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + + # Step 4: Count the number of children per municipality with assistance hours > 0 + df2: pd.DataFrame = df666.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].count() + + # Step 5: Sum the assistance hours per municipality + df2bis: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 6: Sum the assistance hours per municipality again (redundant step) + df4: pd.DataFrame = self.df.groupby("Com_code", as_index=False)[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + # Step 7: Merge all aggregated DataFrames into a consolidated DataFrame `dfx` + dfx: pd.DataFrame = pd.merge(df1, df2, on="Com_code", how="outer") + dfx = pd.merge(dfx, df2bis, on="Com_code", how="outer") + dfx = pd.merge(dfx, df4, on="Com_code", how="outer") + + # Step 8: Rename the columns for clarity + dfx.columns = [ + "Com_code", + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Numero bambini report Comuni", + "Ore di assistenza report Comuni", + "Ore totali rendicontate per il 2023", + ] + # Sort the DataFrame by "Com_code" in ascending order + dfx = dfx.sort_values(by='Com_code', ascending=True) + + # Step 9: Merge with `df_gemeinden` on "Com_code" + dfx = pd.merge(dfx, df_gemeinden, on='Com_code', how='outer') + + # Step 10: Merge with `df_allegato666` on "Com_code" + lingua: str = df_allegato666.iloc[0, 8] # Assuming column index 8 contains language code + dfx = pd.merge(dfx, df_allegato666, on='Com_code', how='outer') + + # Step 11: Drop unnecessary columns and rename others for consistency + columns_to_drop: list = [ + 'Comune provenienza bambino', + f"Somma Giorni Assistenza Anno Riferimento {self.ANNO_RIFERIMENTO}", + "Ore totali rendicontate per il 2023", + 'PLZ', + 'Bezirk', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione' + ] + dfx = dfx.drop(columns=columns_to_drop, axis=1) + dfx = dfx.rename(columns={ + 'Numero utenti': 'Numero utenti allegato 666', + 'Ore di servizio': 'Ore di servizio allegato 666' + }) + + # Step 12: Sort and rename columns based on the language code + if lingua == '001': + dfx = dfx.sort_values(by='Comune') + dfx = dfx.rename(columns={'Comune': 'Comune provenienza bambino'}) + dfx = dfx.drop('Gemeinde', axis=1) + elif lingua == '006': + dfx = dfx.sort_values(by='Gemeinde') + dfx = dfx.rename(columns={'Gemeinde': 'Comune provenienza bambino'}) + dfx = dfx.drop('Comune', axis=1) + + # Step 13: Reorder columns to the desired sequence + columns_order: list = dfx.columns.tolist() + columns_order.insert(1, columns_order.pop(columns_order.index('Comune provenienza bambino'))) + columns_order.insert(2, columns_order.pop(columns_order.index('Numero utenti allegato 666'))) + columns_order.insert(3, columns_order.pop(columns_order.index('Numero bambini report Comuni'))) + columns_order.insert(4, columns_order.pop(columns_order.index('Ore di servizio allegato 666'))) + columns_order.insert(5, columns_order.pop(columns_order.index('Ore di assistenza report Comuni'))) + dfx = dfx[columns_order] + + # Step 14: Replace NaN or empty values with zero + dfx = dfx.fillna(0) + + # Step 15: Insert comparison columns to verify consistency between data sources + dfx.insert(4, 'Confronto bambini', dfx['Numero utenti allegato 666'] == dfx['Numero bambini report Comuni']) + dfx.insert(7, 'Confronto ore', dfx['Ore di servizio allegato 666'] == dfx['Ore di assistenza report Comuni']) + + # Step 16: Calculate the sum for specified columns and append as a summary row + columns_to_sum: list = [ + 'Numero utenti allegato 666', + 'Numero bambini report Comuni', + 'Ore di servizio allegato 666', + 'Ore di assistenza report Comuni' + ] + sum_values: pd.Series = dfx[columns_to_sum].sum() + sum_df: pd.DataFrame = pd.DataFrame([sum_values], index=['Somma']) + dfx = pd.concat([dfx, sum_df]) + + # For columns not included in the sum, add NaN in the summary row + for col in dfx.columns: + if col not in columns_to_sum: + dfx.loc['Somma', col] = pd.NA + + # Step 17: Display the final table in an expandable section within Streamlit + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # Add an empty row for formatting purposes + riga_vuota: dict = {"Annotazione": " "} + nuova_riga_df: pd.DataFrame = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Add a row indicating the generation date of the file + riga_vuota = { + "Annotazione": f"file generato in data: {date.today().strftime('%d/%m/%Y')}" + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + # Build grid options for AgGrid + gridOptions = self.buildGrid(dfx) + + # Provide an option to download the consolidated DataFrame as an Excel file + self.download_excel_file( + dfx, + "calcolo_bimbi_per_tipologia_comune_ore.xlsx", + "casospeciale" + ) + + # Display the DataFrame in an interactive grid + AgGrid( + dfx, + gridOptions=gridOptions, + enable_enterprise_modules=True + ) + # Note: No flag is set here as it's not required + + # we take only the rows where we found an inconsistency + self.df_calcolo_666 = dfx[(dfx['Confronto bambini'] == False) | (dfx['Confronto ore'] == False)] + + # Note: Ensure that all referenced variables and methods (e.g., df_gemeinden, df_allegato666, NO_ZERO, etc.) are defined within the class or passed appropriately. + + def errOreRendicontateZero(self) -> None: + """ + Metodo per trovare e elencare i bambini con ore totali rendicontate a zero. + + Parameters: + None + + Returns: + None + """ + + condizione: pd.Series = ( + self.df["Ore di assistenza ai sensi della delibera n. 666/2019"] == 0 + ) + condizione_logica: pd.Series = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(self.df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errDateAnnoRiferimento(self) -> None: + """ + Check for incongruences in the start and end dates of the contract compared to the reference year. + """ + # Check if the start date is after the reference year + condizione_anno_inizio: pd.Series = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + + # Check if the end date is before the reference year + condizione_anno_fine: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ].dt.year < int(self.ANNO_RIFERIMENTO) + + # Combine the conditions and apply the NO_ZERO filter + condizione_logica: pd.Series = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp: pd.DataFrame = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errIncongruenzaDateAnnoRiferimento", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self) -> None: + """ + Check if there are any records where the start date of the contract is after the end date. + """ + # Create a boolean condition for when the start date is greater than the end date + inizio_minore_fine: pd.Series = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto (o data fine assistenza se diversa)"] + ) + + # Combine this condition with NO_ZERO filter + condizione_logica: pd.Series = inizio_minore_fine & NO_ZERO + + # If there are any such records, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + + # Create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + # If required, convert date columns to string format + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values( + by=["Cognome","Nome"] + ), + "errInizioMinoreFinex", + ) + + # Set the flag for errors in the original dataframe + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self) -> None: + """ + Check if the age of a child is less than 90 days. + Args: + None + Returns: + None + """ + + # Convert columns to datetime + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] = pd.to_datetime( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + ) + self.df["Data di nascita"] = pd.to_datetime(self.df["Data di nascita"]) + + # Then compute the difference + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + #st.write(giorni) + #st.write(self.df[giorni]) + + # Combine the condition with the NO_ZERO filter + condizione_logica: pd.Series = giorni & NO_ZERO + #st.write(self.df[condizione_logica]) + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_eta_bambino.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errAgeChildx", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errFineAssistenzaMax4Anni(self) -> None: + """ + Check if the end date of assistance is more than 4 years from the birthdate. + Args: + None + Returns: + None + """ + + # Calculate the number of days between the end date and the birthdate + giorni = ( + self.df["Data fine contratto (o data fine assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + # Combine the condition with the NO_ZERO filter + condizione_logica = giorni & NO_ZERO + + # If there are any incongruences, create an expander section to display them + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + + # Sort the dataframe and create a temporary dataframe for display + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Download the sorted dataframe to an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome","Nome"]), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome","Nome"]), + "errFineAssistenzaMax4Annix", + ) + + # Set the flag for incongruences in the original dataframe + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten(self) -> None: + """ + Validates kindergarten-related data for each child in the DataFrame. + + This method performs the following operations: + 1. Checks if the child's birth date is earlier than a specified control date. + 2. Verifies that the contract end date is within an acceptable range based on the birth year. + 3. Applies additional conditions based on the reference year. + 4. Aggregates and identifies records with inconsistencies. + 5. Displays the errors in an expandable section within Streamlit. + 6. Provides options to download the error data and displays it in an interactive grid. + 7. Flags the erroneous records in the main DataFrame. + + --> #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for the operations. + Exception: For any other exceptions that occur during execution. + """ + try: + # Ensure necessary columns are present + required_columns = { + "Data di nascita", + "Data fine contratto (o data fine assistenza se diversa)", + "Cognome", + "Nome" + } + if not required_columns.issubset(self.df.columns): + missing = required_columns - set(self.df.columns) + raise KeyError(f"Colonne mancanti: {missing}. Impossibile proseguire con il controllo 'Kindergarten'") + return + + # Convert relevant columns to datetime if not already + self.df["Data di nascita"] = pd.to_datetime( + self.df["Data di nascita"], format="%d.%m.%Y", errors='coerce' + ) + self.df["Data fine contratto (o data fine assistenza se diversa)"] = pd.to_datetime( + self.df["Data fine contratto (o data fine assistenza se diversa)"], format="%d.%m.%Y", errors='coerce' + ) + + # Define control date from constants + controllo_kinder_date: pd.Timestamp = pd.to_datetime( + self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"], format="%d.%m.%Y" + ) + + # Step 1: Check if "Data di nascita" is earlier than the control date + data_nascita: pd.Series = self.df["Data di nascita"] < controllo_kinder_date + + # Step 2: Compute the acceptable contract end date ("04.09.{birth_year + 3}") + # Extract birth year and compute birth_year + 3 + birth_year_plus_3: pd.Series = self.df["Data di nascita"].dt.year + 3 + + # Create a Series of "04.09.{birth_year + 3}" as datetime + acceptable_end_date: pd.Series = pd.to_datetime( + "04.09." + birth_year_plus_3.astype(str), format="%d.%m.%Y", errors='coerce' #modificato in '04.09' il 24/6/2024 su richiesta RobertaB + ) + + # Compare "Data fine contratto..." with the acceptable end date + data_fine_ass: pd.Series = self.df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] > acceptable_end_date + + # Step 3: Apply additional condition if reference year is "2020" + if self.ANNO_RIFERIMENTO == "2020": + # Define an additional birth date condition + additional_birth_date_condition: pd.Series = self.df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y", errors='coerce' + ) + # Combine all conditions + condizione_logica: pd.Series = data_nascita & additional_birth_date_condition & data_fine_ass & NO_ZERO + else: + # Combine conditions without the additional birth date condition + condizione_logica: pd.Series = data_nascita & data_fine_ass & NO_ZERO + + # Step 4: Check if any errors are found + if condizione_logica.any(): + num_errori: int = condizione_logica.sum() + expndr = st.expander( + f"Trovato errore Kindergarten ({num_errori} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine > 04.09 dell'anno di nascita + 3 anni" + ) + + # Filter the DataFrame for error records + dftemp: pd.DataFrame = self.df.loc[condizione_logica].copy() + + # Optional: Convert date columns to strings if required by the interface + if hasattr(interface, 'CONVERTIDATESTRINGHE') and interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Provide a downloadable Excel file with sorted error records + dftemp_sorted = dftemp.sort_values(by=["Cognome", "Nome"]) + self.download_excel_file( + dftemp_sorted, + "errori_kindergarten.xlsx", + ) + + # Display the error records in an interactive grid within Streamlit + self.make_grid( + dftemp_sorted, + "errKindergartenx", + ) + + # Flag the erroneous records in the main DataFrame + erroneous_cf = dftemp_sorted["Data di nascita"].unique() # Adjust if "Codice fiscale" is needed + self.df.loc[ + condizione_logica, + "errKindergarten", + ] = True + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def errGesamtstundenVertragszeitraum(self) -> None: + """ + Identifies and handles errors related to overlapping contract periods + across different municipalities for the same "Codice fiscale" (tax code). + + This method performs the following steps: + 1. Finds tax codes present in multiple municipalities. + 2. Identifies overlapping contract periods for these tax codes across different municipalities. + 3. Filters and sorts the relevant data for reporting. + 4. Checks if the calculated hours exceed the reported hours based on a reference year. + 5. If errors are found, it displays warnings, provides detailed information, and + allows downloading the error data as an Excel file. + + The method updates the DataFrame `self.df` by setting a flag for rows where + the proportion of calculated hours is less than the sum of reported hours. + + Raises: + KeyError: If expected columns are missing from `self.df`. + ValueError: If data types are incompatible for calculations. + """ + # Step 1: Identify tax codes ("Codice fiscale") present in multiple municipalities + # Group by "Codice fiscale" and count the number of unique "Comune" (municipality) entries + multi_city_codes: List[str] = self.df.groupby("Codice fiscale")["Comune"].nunique() + multi_city_codes = multi_city_codes[multi_city_codes > 1].index.tolist() + + # Filter the DataFrame to include only rows with tax codes in multiple municipalities + df_multi = self.df[self.df['Codice fiscale'].isin(multi_city_codes)] + + # Step 2: Find overlapping contract periods in different municipalities + # Merge the DataFrame with itself on "Codice fiscale" to compare different records + merged_df = df_multi.merge( + df_multi, on="Codice fiscale", suffixes=("_1", "_2") + ) + # Keep only rows where the municipality is different + merged_df = merged_df[merged_df["Comune_1"] != merged_df["Comune_2"]] + + # Define the condition for overlapping contract periods + overlap_condition = ( + merged_df["Data inizio contratto (o data inizio assistenza se diversa)_1"] + <= merged_df["Data fine contratto (o data fine assistenza se diversa)_2"] + ) & ( + merged_df["Data fine contratto (o data fine assistenza se diversa)_1"] + >= merged_df["Data inizio contratto (o data inizio assistenza se diversa)_2"] + ) + + # Apply the overlap condition to filter overlapping pairs + overlapping_pairs = merged_df[overlap_condition] + + # Extract unique tax codes that have overlapping periods + result_codes_list = overlapping_pairs["Codice fiscale"].unique().tolist() + + # Step 3: Filter the original DataFrame for the identified tax codes + filtered_df = self.df[self.df["Codice fiscale"].isin(result_codes_list)] + result_df = filtered_df[ + [ + "Cognome", + "Nome", + "Comune", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "filename", + ] + ].reset_index(drop=True) + # Sort the result DataFrame by "Cognome" and "Nome" + result_df = result_df.sort_values(by=["Cognome", "Nome"]) + self.df_bambini_che_impediscono_controllo_superamento_ore = result_df + + # Step 4: Calculate the number of days in the reference year + # Assuming self.ANNO_RIFERIMENTO is a string representing the year, e.g., "2023" + nrGiorniAnnoRiferimento = pd.Period( + f"{self.ANNO_RIFERIMENTO}-12-31", freq="D" + ).day_of_year + + # Calculate the condition where calculated hours exceed reported hours + # Note: 1920 is a constant multiplier; adjust as necessary + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # Note: 365 only if not a leap year + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ].transform("sum").astype("float") + + # Combine the above condition with another condition (NO_ZERO) + # Assuming NO_ZERO is defined elsewhere in the class + condizione_logica = condizioneerrore2 & NO_ZERO + + # Step 5: If any rows meet the error condition, process and report them + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica].copy() + # Insert a new column "Ore calcolate" with the calculated hours + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + # Create an expandable section in Streamlit to display warnings and information + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errore/i)" + ) + with expndr: + st.warning( + "Attenzione: i seguenti bambini non sono stati considerati per il controllo poiché hanno periodi uguali o sovrapposti per comuni diversi." + ) + st.write(result_df) + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate {self.ANNO_RIFERIMENTO})" + ) + + # Convert date columns to strings if necessary + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + # Provide options to download the error data as an Excel file + self.download_excel_file( + dfx.sort_values(by=["Cognome", "Nome"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + # Display the error data in a grid format + self.make_grid( + dfx.sort_values(by=["Cognome", "Nome"]), + "errGesamtstundenVertragszeitraumx", + ) + + # Set a boolean flag in the original DataFrame for the identified errors + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + def errSuperatoOreMassime1920(self) -> None: + """ + Identifies and handles cases where the total rendered hours per child exceed 1920. + + This method performs the following operations: + 1. Calculates the total hours rendered per child based on the "Codice fiscale". + 2. Identifies records where the total hours exceed 1920 and meet the `NO_ZERO` condition. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns are missing from `self.df`. + AttributeError: If required attributes or methods are not defined in the class. + """ + # Step 1: Calculate the total rendered hours per child ("Codice fiscale") + # Group by "Codice fiscale" and sum the "Ore di assistenza ai sensi della delibera n. 666/2019" + total_hours = ( + self.df.groupby("Codice fiscale")[ + "Ore di assistenza ai sensi della delibera n. 666/2019" + ] + .transform("sum") + .astype(float) + ) + + # Define the condition where total hours exceed 1920 + condizionelogica2: pd.Series = total_hours > 1920 + + # Combine with another condition `NO_ZERO` to filter relevant records + # Assuming `NO_ZERO` is a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizionelogica2 & NO_ZERO + + # Step 2: Check if any records meet the error condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920." + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3a: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + # Step 3b: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errSuperatoOreMassime1920x", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errSuperatoOreMassime1920' to True for affected rows + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + def errBambinoInPiuComuni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") is present in more than one municipality. + + This method performs the following operations: + 1. Determines if any child is associated with multiple municipalities based on the "Codice fiscale". + 2. If such cases exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Codice fiscale", "Comune", "Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Identify children present in multiple municipalities + # Group the DataFrame by "Codice fiscale" and count the number of unique "Comune" entries + condizionlogica1: pd.Series = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + + # Note: Previously combined with `NO_ZERO`, but removed to include all cases of multiple municipalities + condizione_logica: pd.Series = condizionlogica1 + + # Step 2: Check if any records meet the condition of being in multiple municipalities + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 3a: Convert date columns to strings if the flag is set + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 3b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_in_piu_comuni.xlsx", + ) + + # Step 3c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errBambinoInPiuComunix", + ) + + # Step 4: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errBambinoInPiuComuni' to True for affected rows + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + def errPresentiAnnotazioni(self) -> None: + """ + Identifies and handles cases where a child ("Bambino") has annotations in their "Cognome" (Surname) or "Nome" (Name). + + This method performs the following operations: + 1. Detects special characters in the "Cognome" and "Nome" columns indicating annotations. + 2. Filters the DataFrame based on the detection and an additional condition `NO_ZERO`. + 3. If such records exist, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + KeyError: If expected columns ("Cognome", "Nome", etc.) are missing from `self.df`. + AttributeError: If required attributes or methods (e.g., `converti_date_in_stringhe`, `download_excel_file`, `make_grid`) are not defined in the class. + """ + # Step 1: Detect annotations in the "Cognome" and "Nome" columns using regex for special characters + # The regex pattern looks for any of the specified special characters + annotation_pattern: str = r"[@_!#$%^&*()<>?/|}{~:]" + condizione: pd.Series = self.df["Cognome"].str.contains( + annotation_pattern, regex=True, na=False + ) & self.df["Nome"].str.contains(annotation_pattern, regex=True, na=False) + + # Step 2: Combine the annotation condition with an additional condition `NO_ZERO` + # `NO_ZERO` is assumed to be a boolean Series defined elsewhere in the class + condizione_logica: pd.Series = condizione & NO_ZERO + + # Step 3: Check if any records meet the combined condition + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {self.df[condizione_logica].shape[0]} errori)" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errPresentiAnnotazionix", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errPresentiAnnotazioni' to True for affected rows + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + def errNomeComuneTagesmutter(self) -> None: + """ + Identifies and handles cases where a child's residence city does not match the official list of cities. + + This method performs the following operations: + 1. Reads the official list of cities from an Excel file. + 2. Checks if the city in the "Comune di residenza assistente domiciliare all'infanzia" column + matches either the "Gemeinde" or "Comune" column in the official list. + 3. If mismatches are found, it: + a. Displays an expandable section in Streamlit with relevant information. + b. Provides an option to download the error data as an Excel file. + c. Displays the error data in a grid format. + d. Flags the identified records in the main DataFrame. + + Raises: + FileNotFoundError: If the "GemeindenComuni.xlsx" file is not found. + KeyError: If expected columns are missing from either the main DataFrame or the official list. + Exception: For any other exceptions that occur during the execution. + """ + # Step 1: Read the official list of cities from an Excel file + try: + dfGemeinden: pd.DataFrame = pd.read_excel("GemeindenComuni.xlsx") + except FileNotFoundError as fnf_error: + st.error(f"File not found: {fnf_error}") + return + except Exception as e: + st.error(f"An error occurred while reading 'GemeindenComuni.xlsx': {e}") + return + + # Ensure that the necessary columns exist in dfGemeinden + required_columns_gemeinden = {"Gemeinde", "Comune"} + if not required_columns_gemeinden.issubset(dfGemeinden.columns): + st.error( + f"The official list must contain the columns: {required_columns_gemeinden}" + ) + return + + # Ensure that the necessary column exists in the main DataFrame + required_columns_main = { + "Comune di residenza assistente domiciliare all'infanzia", + "Cognome", + "Nome", + "filename", + } + if not required_columns_main.issubset(self.df.columns): + st.error( + f"The main DataFrame must contain the columns: {required_columns_main}" + ) + return + + # Step 2: Check if the city matches either "Gemeinde" or "Comune" in dfGemeinden + # Create boolean Series indicating matches + condizione1: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2: pd.Series = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione: pd.Series = condizione1 | condizione2 + + # Step 3: Identify records where the city does not match the official list + condizione_logica: pd.Series = ~condizione + + # Step 4: Check if any mismatches exist + if not self.df[condizione_logica].empty: + # Create an expandable section in Streamlit to display error information + expndr = st.expander( + f"Trovati {self.df[condizione_logica].shape[0]} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + with expndr: + # Display informational message about the errors found + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + + # Extract the subset of the DataFrame that meets the error condition + dftemp: pd.DataFrame = self.df[condizione_logica].copy() + + # Step 4a: Convert date columns to strings if the interface requires it + if ( + hasattr(interface, "CONVERTIDATESTRINGHE") + and interface.CONVERTIDATESTRINGHE + ): + dftemp = self.converti_date_in_stringhe(dftemp) + + # Step 4b: Provide an option to download the error data as an Excel file + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + "errori_bambini_con_annotazioni.xlsx", + ) + + # Step 4c: Display the error data in a grid format within Streamlit + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + + # Step 4d: Flag the identified records in the main DataFrame + # This sets a boolean flag 'errNomeComuneTagesmutter' to True for affected rows + self.df.loc[condizione_logica, "errNomeComuneTagesmutter"] = True + + # Optional: Clean up by deleting the official list DataFrame to free memory + del dfGemeinden + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT, df_gemeinden, df_traeger): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + self.df_gemeinden = df_gemeinden + self.df_traeger = df_traeger + self.errori = {} + self.errori["critici"] = {} + self.errori["non critici"] = {} + #self.errori["critici"]["filename"] = [] + #self.errori["non critici"]["filename"] = [] + + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + #self.errori["filename"] = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + c1,c2 = st.columns([3,2]) + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO in ["2023"]: + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:M") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:M") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + # alla prima occorrenza di un errore per un dato filename, inizializziamo la lista di errori + if file.name not in self.errori["critici"]: + self.errori["critici"][file.name] = [] + + self.errori["critici"][file.name].append("Non ha il foglio con nome o ita o deu e non viene usato") + + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alle aspettative" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non è un file Excel o non corrisponde alle aspettative") + + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + + contatorefile += 1 + c1.info(f"Sto elaborando {file.name}...") + + df, flag = self.prepare_data(df, file, c2) + if flag == 1: + pass + elif flag ==2: + c2.error("----> ERRORE - vedi riga sotto...") + else: + c2.success("----> OK") + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + #st.write(df) + self.dataframes.append(df) + #st.write(df) + #c2.success("Elaborazione OK") + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error(f"Errore durante concatenamento dei dataframe caricati: errore: {e}") + st.error("Elaborazione interrotta") + st.stop() + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file, c2): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + flag = None + #st.write(df) + if self.ANNO_RIFERIMENTO in ["2023"]: + df.columns = [ + "Numero progressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "CognomeAssDom", + "NomeAssDom", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto (o data fine assistenza se diversa)", + "Ore di assistenza ai sensi della delibera n. 666/2019", + "Colonna_L_da_cancellare_dopo", + "Codice Comune_TM", + ] + + codice_ente = df.iloc[2,12] + codice_comune = df.iloc[4, 12] + anno = df.iloc[0,5] + + try: + nome_comune = df_gemeinden[df_gemeinden['Com_code'] == codice_comune]['Comune'].values[0] + except: + st.error(f"Errore: manca il codice comune dell'ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice comune dell'ente") + + flag = 2 + return None, flag + + try: + nome_ente = df_traeger[df_traeger['Coop_code'] == codice_ente]['Körperschaft'].values[0] + except: + st.error(f"Errore: manca il codice ente nel file {file.name}, il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Manca il codice dell'ente") + + flag = 2 + return None, flag + + + if codice_comune not in self.df_gemeinden["Com_code"].values: + #c2.warning("ATTENZIONE!") + st.warning( + f"L'ente '{nome_ente}' ha inserito un codice comune non corretto: '{codice_comune}'. \n\r Il file non verra' usato. \n\rIl nome file e': {file.name}" + ) + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato codice comune non corretto") + + flag = 2 + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + return None, flag + + + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", nome_comune) + df.insert(1, "Ente", nome_ente) + df.insert(1, "Com_code", codice_comune) + df.insert(1,"Anno", anno) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero progressivo"] == "*" + df.loc[cond, "Cognome"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero progressivo"] = pd.to_numeric( + df["Numero progressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore nella colonna del **Codice fiscale** + # in questo modo eliminiamo le righe inutili + validi = df["Codice fiscale"].notna() + + # teniamo solo record validi + if not df[validi].empty: + df = df[validi] + else: + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' non contiene dati validi - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Non contiene dati validi") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # controlliamo subito se mancano valore per le ore rendicontate + # se mancano, non usiamo l'Excel + if df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum(): + somma = df["Ore di assistenza ai sensi della delibera n. 666/2019"].isnull().sum() + c2.warning("Attenzione!") + st.error(f"Il file Excel '{file.name}' contiene {somma} valori mancanti per le ore rendicontate - il file non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovati {somma} valori mancanti per le ore rendicontate") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + return None, flag + + # Check only rows where "Numero progressivo" is present + valid_progressivi = df["Numero progressivo"].notna() + duplicates = df[valid_progressivi]["Numero progressivo"].duplicated(keep=False) + + if not df[valid_progressivi][duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + c2.warning("ATTENZIONE! Vedi riga sotto...") + flag = 1 + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri NON progressivi nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri non progressivi") + + df_no_index = ( + df.loc[valid_progressivi & duplicates, ["Numero progressivo", "Cognome", "Nome"]] + .groupby("Numero progressivo", as_index=False) + .first() + ) + df_no_index["Numero progressivo"] = df_no_index["Numero progressivo"].astype(int) + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + condizione_righe_vuote = (~df["Numero progressivo"].isna() & df["Codice fiscale"].isna()) + + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + #c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito numeri progressivi per righe vuote \n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovati numeri progressivi per righe vuote. Le righe vuote sono state eliminate.") + + flag = 1 + + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + condizione_nr_progressivo_assente_ma_righe_con_dati = (df["Numero progressivo"].isna() & ~df["Codice fiscale"].isna()) + + if not df[condizione_nr_progressivo_assente_ma_righe_con_dati].empty: + conta_righe = condizione_nr_progressivo_assente_ma_righe_con_dati.sum() + c2.warning("Attenzione!") + st.warning( + f"Attenzione: l'ente '{nome_ente.upper()}' ha inserito righe con dati ma senza numero progressivo" # nel file {file.name}" + ) + if file.name not in self.errori: + self.errori["non critici"][file.name] = [] + self.errori["non critici"][file.name].append("Trovate righe con dati ma senza numero progressivo") + + flag = 1 + + df = df[~condizione_nr_progressivo_assente_ma_righe_con_dati] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto (o data fine assistenza se diversa)"] + ) + df.loc[ + condizione, "Data fine contratto (o data fine assistenza se diversa)" + ] = datetime(int(self.ANNO_RIFERIMENTO), 12, 31, 0, 0, 0) #str(self.ANNO_RIFERIMENTO) + "-12-31 00:00:00" + + try: + df = self.validate_dates(df,"Data di nascita",file) + if df is None: + return None, flag + + except Exception as e: + c2.error("Errore!") + st.error(f"{file.name} --> Unexpected error occurred: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Trovato errore critico non identificato") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data fine contratto (o data fine assistenza se diversa)",file) + if df is None: + return None, flag + + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data fine contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + try: + df = self.validate_dates(df, "Data inizio contratto (o data inizio assistenza se diversa)", file) + if df is None: + return None, flag + except Exception as e: + c2.warning("Errore!") + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}.\n\rIl file Excel non verra' usato") + + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append("Data inizio contratto contiene valori non data") + + flag = 2 + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None, flag + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + if 'Colonna_L_da_cancellare_dopo' in df.columns: + del df['Colonna_L_da_cancellare_dopo'] + + #c2.success("OK") + return df, flag + + # Function to check for incorrect year format + def is_incorrect_year(self, date_str: str) -> bool: + """ + Check if the year part of a date string is in the correct format. + + Args: + date_str (str): The date string to be checked. + + Returns: + bool: True if the year length is not 4, False otherwise. + """ + year_part = str(date_str).split('-')[-3] + return len(year_part) != 4 # Check if the year length is not 4 + + # Function to check and convert date formats with year validation + def validate_dates(self, df: pd.DataFrame, date_column: str, file) -> Optional[pd.DataFrame]: + """ + Validate and convert date formats in a specified column of a DataFrame. + + Args: + df (pd.DataFrame): The input DataFrame containing the date column. + date_column (str): The name of the column to be validated and converted. + file (FileStorage): The uploaded file object for displaying errors. + + Returns: + pd.DataFrame or None: The modified DataFrame if all dates are valid, otherwise None. + """ + + + if not isinstance(df, pd.DataFrame): + st.write(type(df)) + raise ValueError("The input 'df' must be a pandas DataFrame.") + + if date_column not in df.columns: + st.write(df.columns) + raise KeyError(f"The specified date_column '{date_column}' does not exist in the DataFrame.") + + # Create a new column for the parsed dates + df["Parsed Date"] = pd.to_datetime(df[date_column], format='%d-%m-%Y', errors='coerce')#.dt.strftime('%d-%m-%Y')#.dt.date + + # Identify rows with invalid dates in the new column + invalid_dates_df = df[df["Parsed Date"].isna()] + + if not invalid_dates_df.empty: + # Display the error message with original wrong dates and additional row information + st.error(f"{file.name} --> {date_column} contiene valori non data; errore: dati non validi.\n\rIl file Excel non verra' usato") + + #st.write(f"Righe con {date_column} invalide:", invalid_dates_df) # Show the full rows + with st.expander(f"Righe con {date_column} invalide:"): + st.write(invalid_dates_df) + if file.name not in self.errori: + self.errori["critici"][file.name] = [] + self.errori["critici"][file.name].append(f"{date_column} contiene valori non data") + + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + + df.drop('Parsed Date', axis=1, inplace=True) + flag = 1 + #st.write(df) + return None + + df[date_column] = df["Parsed Date"] + df.drop('Parsed Date', axis=1, inplace=True) + + return df + + def compute_hours(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Compute the number of hours based on contract start and end dates. + + Args: + df (pd.DataFrame): The input DataFrame containing the date columns. + + Returns: + pd.DataFrame: Modified DataFrame with computed hours. + """ + ar = int(self.ANNO_RIFERIMENTO) # Convert anno riferimento to an integer + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto (o data fine assistenza se diversa)" + ] + + # If the start date is before the reference year, set it to January 1st of the reference year + iniz = df["inizioNorm"].dt.year < ar # Logical condition + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # Find values less than the reference year and replace with 01/01 + fin = df["fineNorm"].dt.year > ar # Logical condition + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # Replace + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # Add a column and set the reference year + return df + + def calcola_giorni_esatti(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self) -> pd.DataFrame: + """ + Method to return the processed data. + Returns: + pd.DataFrame: The DataFrame containing the processed data. + """ + return self.data + + def make_bool_columns(self, df: pd.DataFrame) -> pd.DataFrame: + """ + Adds boolean columns for each error in ERRORDICT for the given year of reference. + + Args: + df (pd.DataFrame): The DataFrame to add boolean columns to. + Returns: + pd.DataFrame: The DataFrame with added boolean columns. + """ + for error_key in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[error_key] = np.nan + df[error_key] = df[error_key].astype("boolean") + + return df + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + #trova_errori = trovaErrori() + + dtype_spec = { + 'Com_code':str #non vogliamo convertire questa colonna to number perche' nell'Excel trovaimo come stringa + } + try: + df_gemeinden = pd.read_excel('../commontools/GemeindenMitKodex.xlsx', dtype = dtype_spec) + df_gemeinden = df_gemeinden[df_gemeinden['PLZ'] != 9999] + + except Exception as e: + st.error(f"Errore durante caricamento file dei comuni; erore: {e}") + st.error("Chiamare Stefan") + st.stop() + + try: + df_traeger = pd.read_excel('../commontools/TM_TraegerMitKodex.xlsx') + except Exception as e: + st.error(f"Errore durante caricamento anagrafica enti; errore: {e}") + st.error("Chiamare Stefan") + st.stop() + + + if interface.submit: + if not interface.uploaded_allegato666: + st.error("L'allegato 666 non e' stato caricato - elaborazione interrotta") + df_allegato666 = None + st.stop() + else: + try: + df_allegato666 = pd.read_excel(interface.uploaded_allegato666) + if df_allegato666 .columns[24] != 666: + st.error(f"Non e' stato trovato il valore di controllo nell'allegato 666; l'elaborazione viene terminata.") + st.stop() + df_allegato666 =df_allegato666.drop(labels=range(0, 8), axis=0) + df_allegato666 =df_allegato666.drop(labels=range(124, 129), axis=0) + cols_to_drop = df_allegato666.columns[10:] + df_allegato666 = df_allegato666.drop(columns=cols_to_drop) + df_allegato666 = df_allegato666.drop(columns='Unnamed: 8') + + #ridefiniamo i nomi delle colonne + df_allegato666.columns = [ + 'Comune provenienza bambino', + 'Numero utenti', + 'Ore di servizio', + 'Costo orario', + 'Costo del servizio', + 'Entrate compartecipazione', + 'Ore tariffa maggiorata', + 'Entrate maggiorazione', + 'Com_code' + ] + if interface.DEBUGGENERAL: + st.write(df_allegato666) + except Exception as e: + st.error(f"Errore durante il caricamento dell'allegato 666: errore: {e}") + st.error("Impossibile proseguire") + st.stop() + + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT, df_gemeinden, df_traeger) + processor.process_data() + + #with interface.TAB3: + # reportmaker = ReportGenerator(self.df, self.df_bambini_che_impediscono_controllo_superamento_ore, self.df_calcolo_666, self.ERRORDICT) + # reportmaker.genera_report() + # self.display_final_table() + + trova_errori = trovaErrori(processor.get_data(), interface, df_gemeinden, df_allegato666) + #st.write(processor.errori) + with interface.TAB3: + reportmaker = ReportGenerator(processor, trova_errori, interface) + reportmaker.genera_report() + reportmaker.display_final_table() + + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + #st.balloons() diff --git a/pages/02_Betriebliche_Kitas_3c.py.off b/pages/02_Betriebliche_Kitas_3c.py.off new file mode 100644 index 0000000000000000000000000000000000000000..eae9bac6c5f40007bf4c28c9ec3a45c6b55595ac --- /dev/null +++ b/pages/02_Betriebliche_Kitas_3c.py.off @@ -0,0 +1,1441 @@ +import numpy as np +import pandas as pd +import datetime as dt +import copy +import this +import collections + +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + + +class valoriEtErrori(): + + ERRORDICT2019 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + #"errSommaOre": "Controllo somma ore 1025 e 666", + } + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + #"errSommaOre": "Controllo somma ore 1025 e 666", + } + + + ERRORDICT2021 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + #"errSommaOre": "Controllo somma ore 1025 e 666", + } + + ERRORDICT2022 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "c": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio maggiore data fine", + #"errInizioAnnoRiferimento": "Data inizio per anno riferimento", + #"errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + #"errSommaOre": "Controllo somma ore 1025 e 666", + } + + ERRORDICT2023 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio maggiore data fine", + #"errInizioAnnoRiferimento": "Data inizio per anno riferimento", + #"errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + #"errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + #"errSommaOre": "Controllo somma ore 1025 e 666", + } + + ERRORDICT = {"2019": ERRORDICT2019, "2020": ERRORDICT2020, "2021": ERRORDICT2021, "2022": ERRORDICT2022, "2023": ERRORDICT2023} + + costanti_2020 = { + "datainiziomin": "01.01.2017", + "datainiziomax": "31.12.2020", + "datafine": "31.12.2023", + "datainizio543": "23.11.2020", + "datafine543": "24.02.2020", + "datafineassistenza_foglio1": "01.01.2020", + "datafineassistenza_foglio0": "01.01.2020", + } + + costanti_2019 = { + "datainiziomin": "01.01.2016", + "datainiziomax": "31.12.2019", + "datafine": "31.12.2022", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2019", + "datafineassistenza_foglio0": "01.01.2019", + } + + costanti_2021 = { + "datainiziomin": "01.01.2018", + "datainiziomax": "31.12.2021", + "datafine": "31.12.2024", + #"datainizio543": "23.11.2019", + #"datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2021", + "datafineassistenza_foglio0": "01.01.2021", + } + + costanti_2022 = { + #"datainiziomin": "01.01.2018", + #"datainiziomax": "31.12.2021", + #"datafine": "31.12.2024", + #"datainizio543": "23.11.2019", + #"datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2022", + "datafineassistenza_foglio0": "01.01.2022", + } + + costanti_2023 = { + #"datainiziomin": "01.01.2018", + #"datainiziomax": "31.12.2021", + #"datafine": "31.12.2024", + #"datainizio543": "23.11.2019", + #"datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2023", + "datafineassistenza_foglio0": "01.01.2023", + } + + COSTANTI = {"2020": costanti_2020, "2019": costanti_2019, "2021": costanti_2021, "2022": costanti_2022, "2023": costanti_2023} + + DIZIONARIO = {"2019" : + {"ERRORDICT" : ERRORDICT2019, + "COSTANTI" : costanti_2019, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 10, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 9, # i valori che si servono per estrarre l'anno in questione dal file Excel + "leggiente" : "yes", #de dobbiamo estrarre nome ente o no dai due fogli di lavoro (dal 2022 in poi: no) + }, + "2020" : + {"ERRORDICT" : ERRORDICT2020, + "COSTANTI" : costanti_2020, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 10, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 9, # i valori che si servono per estrarre l'anno in questione dal file Excel + "leggiente" : "yes", #de dobbiamo estrarre nome ente o no dai due fogli di lavoro (dal 2022 in poi: no) + }, + "2021" : + {"ERRORDICT" : ERRORDICT2021, + "COSTANTI" : costanti_2021, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 9, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 8, # i valori che si servono per estrarre l'anno in questione dal file Excel + "leggiente" : "yes", #de dobbiamo estrarre nome ente o no dai due fogli di lavoro (dal 2022 in poi: no) + }, + + "2022" : + {"ERRORDICT" : ERRORDICT2022, + "COSTANTI" : costanti_2022, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 9, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 8, # i valori che si servono per estrarre l'anno in questione dal file Excel + "leggiente" : "no", #de dobbiamo estrarre nome ente o no dai due fogli di lavoro (dal 2022 in poi: no) + }, + + "2023" : + {"ERRORDICT" : ERRORDICT2023, + "COSTANTI" : costanti_2023, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 8, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 7, # i valori che si servono per estrarre l'anno in questione dal file Excel + "leggiente" : "no", #de dobbiamo estrarre nome ente o no dai due fogli di lavoro (dal 2022 in poi: no) + } + } + + + + +class make_interface(): + + st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="👽" # 👽 🤗 + ) + + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori BETRIEBLICHE KITAS (v. 1.1)") + st.sidebar.markdown(f"### Impostazioni controlli BETRIEBLICHE KITAS") + + def __init__(self, DIZIONARIO): + #self.ERRORDICT = ERRORDICT + #currentDateTime = dt.datetime.now() + #date = currentDateTime.date() + #year = date.strftime("%Y") + + self.ANNO_RIFERIMENTO = st.sidebar.selectbox("ANNO RIFERIMENTO", ("2019", "2020", "2021", "2022","2023"), index=4) + self.DEBUGMODE = st.sidebar.checkbox("Debug sovrapposizione temporale") + self.DEBUGWARNINGS = st.sidebar.checkbox("Interrompere con warnings") + self.TOLLERANZAZERO = st.sidebar.checkbox("Tolleranza zero") + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox("Mostra costanti per anno riferimento") + if self.MOSTRACOSTANTI: + #or k in DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"]: + # st.sidebar.info(k + " " + DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"][k]) + st.sidebar.info(DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"]) + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + try: + self.ERRORDICT = DIZIONARIO[self.ANNO_RIFERIMENTO]["ERRORDICT"] + except Exception as e: + self.STATUS.error("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + if self.TOLLERANZAZERO: st.stop() + + self.make_form() + self.choose_files() + self.choose_checks() + #self.make_tabs() + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + + # Create an expander to hold the checkboxes + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + + # If the error dictionary is not empty + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox("Selezionare/deselezionare tutti i controlli", value=True) + + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[f"c{a}"].checkbox( + valore_errore, value=attivatutti, key=chiave_errore + ) + + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a = a + 1 + + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + if self.TOLLERANZAZERO: + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3, self.TAB4 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI NEI DATI", + "SOVRAPPOSIZIONI TEMPORALI", + "TABELLE FINALI", + ] + ) + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def make_grid(self, df, key): + # togliamo le colonne bool + df = self.drop_columns(df) + gridOptions = self.buildGrid(df) + AgGrid(df, gridOptions=gridOptions, enable_enterprise_modules=True, key=key) + #return dfgrid + + def drop_columns(self, df): + # toglie le colonne bool + for chiave_errore in self.ERRORDICT.items(): + df = df.drop([chiave_errore[0]], axis=1) + return df + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + #gb.configure_selection(selection_mode="multiple", use_checkbox=True) + #gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + #) + gridOptions = gb.build() + return gridOptions + + +class trova_errori(): + + dffinal = None + + def __init__(self, dizionario, interface, df): + self.checks = interface.checks + + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.COSTANTI = dizionario[self.ANNO_RIFERIMENTO]["COSTANTI"] + self.df = df + self.check_data() + + + + + def check_data(self): + """ + Iterate over the checks and call the relevant method for each checked item. + Display tables summarizing the data on sheets 0 and 1. + Save sheets 0 and 1 as Excel files. + """ + + with interface.TAB2: + if interface.DEBUGGENERAL: st.info("entered check_data") + + # Iterate over the checks and call the relevant method for each checked item. + for check, enabled in self.checks.items(): + if check == "errTimeSeries": + continue + if enabled: + if interface.DEBUGGENERAL: st.write(check) + + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + getattr(self, check)() + except KeyError: + st.error(f"La funzione {check} non è stata trovata.") + except Exception as e: + st.error(f"Si è verificato un errore nella funzione {check}: {str(e)}") + if interface.TOLLERANZAZERO: + st.stop() + + with interface.TAB3: + # Call the errTimeSeries method. + try: + self.errTimeSeries() + except KeyError: + st.error("La funzione errTimeSeries non è stata trovata.") + except Exception as e: + st.error(f"Si è verificato un errore nella funzione errTimeSeries: {str(e)}") + if interface.TOLLERANZAZERO: + st.stop() + + with interface.TAB4: + # Display tables summarizing the data on sheets 0 and 1. + expndr = st.expander("TABELLA RIASSUNTIVA ELENCO UTENTI PRECEDENTI (FOGLIO 0)") + with expndr: + st.info("Tabella riassuntiva elenco utenti precedenti") + interface.make_grid( + self.df["sheet0"].sort_values(by=["DataInizio"]), "riassunto0" + ) + + expndr = st.expander("TABELLA RIASSUNTIVA ELENCO UTENTI (FOGLIO 1)") + with expndr: + st.info("Tabella riassuntiva elenco utenti") + interface.make_grid( + self.df["sheet1"].sort_values(by=["DataInizio"]), "riassunto1" + ) + + # Save sheets 0 and 1 as Excel files. + self.df["sheet0"].to_excel("pippuzzo0.xlsx") + self.df["sheet1"].to_excel("pippuzzo1.xlsx") + + + + def errPluriNominato(self): + + # qui scegliamo una soluzione diversa dal solito + # lavoriamo con *insiemi* + # creiamo nuovo df con nomi che hanno stessa data inizio su entrambi i fogli + df_same_data_inizio = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataInizio"], how="inner") + + # creiamo nuovo df con nomi che hanno stessa data fine su entrambi i fogli + df_same_data_fine = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataFine"], how="inner") + + # se uno dei due df non è vuoto abbiamo la condizione di errore + if not df_same_data_inizio.empty or not df_same_data_fine.empty: + expndr = st.expander("Trovati bambini con stessa data inizio o stessa data fine o entrambe le date uguali (in riferimento ai due fogli)") + with expndr: + st.info("Tabella con utenti che hanno la stessa data inizio o fine o entrambi (in riferimento ai due fogli)") + # uniamo i due df con un outer join + df_same_data = pd.merge( + df_same_data_inizio, + df_same_data_fine, + on=["Cognome", "Nome"], + how="outer", + ) + + # facciamo la aggrid qui per semplicità anche se non è soluzione elegante + gridOptions = interface.buildGrid(df_same_data) + AgGrid( + df_same_data, + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="same_data_fine_inizio", + ) + + # non definiamo le colonne bool, visto l'approccio usato + + def errTimeSeries(self): + + #with interface.TAB3: + + # st.info("") + st.info("SOVRAPPOSIZIONI TEMPORALI UTENTI COMUNALI E AZIENDALI - CANDIDATI PER ESCLUSIONE") + # questo è il controllo più complesso, still work in progress + + # aggiungiamo la colonna *delibera666* perché dopo ci serve + self.df["sheet0"]["delibera666"] = 0 + + # creiamo una lista con entrambi i df + # possiamo dire quale colonne prendere dal sheet1 con la sintassi che segue + frames = [ + self.df["sheet0"], + self.df["sheet1"][ + [ + "Ente", + "Microstruttura", + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + ] + ], + ] + + # uniamo i due df - ora i contenuti di sheet0 e sheet1 sono in un unico df + result = pd.concat(frames) + result = result.drop("filename", axis=1) + # ordiniamo tutto per data inizio + result = result.sort_values(by=["DataInizio"]) + + # dobbiamo intercettare ed eliminare righe con lo stesso Cognome, Nome, Utenza, DataInizio, DataFine + # bisogna vedere se questa soluzione va bene + + result.drop_duplicates(subset=["Cognome", "Nome", "utente", "DataInizio", "DataFine"], inplace=True) + + # resettiamo l'indice in modo che inizi da 0 + result = result.reset_index() + # potrebbe servire per debug + if interface.DEBUGMODE: + try: + result.to_excel("dataframePrimaDiAlgoritmo.xlsx") + except Exception as e: + st.error("Could not save dataframe to file, reason: " + str(e)) + if interface.TOLLERANZAZERO: st.stop() + + # inizializziamo i contatori per utenti comunali e aziendali + cont_a = 0 + cont_c = 0 + + # inizializziamo le liste con le date fine incontrate durante l'iterazione sui record del df + datafineprecedenti_c = [] + datafineprecedenti_a = [] + + datafine_c = collections.namedtuple('Data',('datafine','nome')) + datafine_a = collections.namedtuple('Data',('datafine','nome')) + + st.write("################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + # dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice + for ind in result.index: + # si tratta di utente comunale? + try: + if result["utente"][ind].lower() == "comunale": + cont_c += 1 # incrementiamo il contatore + # datafineprecedenti_c.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + datafine = datafine_c(str(result["DataFine"][ind]), str(result["Cognome"][ind]) + " " + str(result["Nome"][ind])) + datafineprecedenti_c.append(datafine) + + d_c = copy.copy(datafineprecedenti_c) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente in (datafineprecedenti_c): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente.datafine): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente comunale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore comunale valore attuale = " + + str(cont_c) + ) + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore comunale = " + str(cont_c) + ", utente relativo alla data trovata: " + datafine_precedente.nome) + d_c.remove(datafine_precedente) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_c = copy.copy(d_c) # deep copy della lista aggiornata (senza data fine "consumate") + + # si tratta di utente aziendale? + elif result["utente"][ind].lower() == "aziendale": + cont_a += 1 # incrementiamo il contatore + # datafineprecedenti_a.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + datafine = datafine_a(str(result["DataFine"][ind]), str(result["Cognome"][ind]) + " " + str(result["Nome"][ind])) + datafineprecedenti_a.append(datafine) + + d_a = copy.copy(datafineprecedenti_a) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente_aziendale in (datafineprecedenti_a): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente_aziendale.datafine): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente aziendale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore aziendale valore attuale = " + + str(cont_a) + ) + cont_a -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore aziendale = " + str(cont_a) + ", utente relativo alla data trovata: " + datafine_precedente_aziendale.nome) + d_a.remove(datafine_precedente_aziendale) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_a = copy.copy(d_a) # deep copy della lista aggiornata (senza data fine "consumate") + + except Exception as e: + st.error(f'Errore {e} per {result["Nome"][ind]} {result["Cognome"][ind]}, utente: {result["utente"][ind]}') + if interface.TOLLERANZAZERO: st.stop() + continue + + if interface.DEBUGMODE: + try: + st.write("STATO ATTUALE CONTATORE: bimbo " + result["utente"][ind].lower() + "\t--> " + result["Cognome"][ind] + " " + result["Nome"][ind] + " \t--> contatore comunale = " + str(cont_c) + " e contatore aziendale = " + str(cont_a)) + except: + st.error(f"ATTENZIONE! Trovato errore per il seguente utente: Cognome = {result['Cognome'][ind]} Nome = {result['Nome'][ind]} utente = {result['utente'][ind]}") + #st.error(f"utente = {result['utente'][ind]}") + #st.error(f"Cognome = {result['Cognome'][ind]}") + #st.error(f"Nome = {result['Nome'][ind]}") + # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta + if ( + (cont_c >= cont_a) + and result["utente"][ind] == "comunale" + and result["DataInizio"][ind] + >= pd.to_datetime("01.01.2018", format="%d.%m.%Y") + ): + + # st.write("trovato!!!!!!!") + try: + st.warning(f"[*] Bimba/o {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {str(result['delibera666'][ind])}") + except: + st.error("nel 666") + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write( + "tolto bimbo: contatore comunale = " + + str(cont_c) + + " e contatore aziendale = " + + str(cont_a) + ) + st.write() + st.write("################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + def errElencoUtenti0(self): # controllo data fine assistenza minore di un certo valore, foglio 0 + """Checks if the 'DataFine' in 'sheet0' is less than a certain value and sets a flag for the corresponding rows. + + Args: + self: Instance of the class. + + Returns: + None. + """ + # Define sheet and condition to check if 'DataFine' is less than a certain value. + sheet = "sheet0" + condizione = self.df[sheet]["DataFine"] < pd.to_datetime(self.COSTANTI["datafineassistenza_foglio0"], format="%d.%m.%Y") + + # Invert the condition and set flag if any rows meet the condition. + if not self.df[sheet][~condizione].empty: + # Create a Streamlit expander to show errors. + expndr = st.expander(f"Trovati errori ELENCO UTENTI PRECEDENTI per anno di riferimento {self.ANNO_RIFERIMENTO} sul PRIMO FOGLIO") + with expndr: + st.info("Tabella con errori ELENCO UTENTI PRECEDENTI in riferimento ad anno di riferimento sul PRIMO FOGLIO") + # Create a grid to display the rows with errors. + interface.make_grid(self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errElencoUtentixxx") + # settiamo flag bool + # Set flag to True for rows that meet the condition. + self.df[sheet].loc[~condizione, "errElencoUtenti0"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + # + + def errTipoKitas(self): + """ + Check for errors in the description of Kitas type for each child. + + If errors are found, set the "errTipoKitas" flag to True in the corresponding dataframe. + + Args: + self (object): instance of class + """ + + for sheet_num in range(2): + sheet_name = f"sheet{sheet_num}" + condizione1 = self.df[sheet_name]["utente"].isin(["comunale", "aziendale"]).notna() + condizione = ~condizione1 + if not self.df[sheet_name][condizione].empty: + expndr = st.expander(f"Trovati errori nella descrizione tipo Kitas nel foglio {sheet_num+1}") + with expndr: + st.info("Errori riscontrati nella descrizione della tipologia Kitas") + interface.make_grid(self.df[sheet_name][condizione].sort_values(by=["Cognome"]), + f"errTipoKitas{sheet_num}",) + # set the bool flag + self.df[sheet_name].loc[condizione, "errTipoKitas"] = True + + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori tipologia Kitas", + # "errTipoKitas", + # ) + + def errDataInizioFine(self): + """Identify occurrences where the start date is later than the end date. + + Returns: + - None + """ + for a in range(2): + # Define sheet name based on current iteration + sheet = f"sheet{a}" + # Define condition for errors + condition = self.df[sheet]["DataInizio"] > self.df[sheet]["DataFine"] + # If there are errors, display them in a Streamlit expander + if not self.df[sheet][condition].empty: + expander = st.expander(f"Errors found: start date later than end date in sheet {a+1}") + with expander: + st.info("Table with errors: start date later than end date.") + interface.make_grid( + self.df[sheet][condition].sort_values(by=["Cognome"]), + f"errDataInizioFine{a}", + ) + # Set boolean flag for errors + self.df[sheet].loc[condition, "errDataInizioFine"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errDataInizioFine", + # ) + + def errNome(self): + """ + Checks for missing first name and/or last name in both sheets, sets error flag if found. + """ + for a in range(2): + sheet = f"sheet{a}" + is_missing_name = pd.isnull(self.df[sheet][["Cognome", "Nome"]]).any(axis=1) + if not self.df[sheet][is_missing_name].empty: + with st.expander(f"Trovati valori nulli per cognome o nome o entrambi nel foglio {a+1}"): + st.info("Tabella con cognome o nome o entrambi assenti") + interface.make_grid( + self.df[sheet][is_missing_name].sort_values(by=["Cognome"]), + f"errNome{a}", + ) + self.df[sheet].loc[is_missing_name, "errNome"] = True + + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # " + + def errInizioAnnoRiferimento(self): + """ + Check if the 'DataInizio' value is within the range defined by the COSTANTI variable for each sheet of the dataframe. + If a value is outside the range, set the 'errInizioAnnoRiferimento' flag to True in the corresponding sheet. + + Args: + None. + + Returns: + None. + """ + for sheet_num in range(2): + sheet = f"sheet{sheet_num}" + min_date = pd.to_datetime(self.COSTANTI["datainiziomin"], format="%d.%m.%Y") + max_date = pd.to_datetime(self.COSTANTI["datainiziomax"], format="%d.%m.%Y") + condizione = (self.df[sheet]["DataInizio"] > min_date) & (self.df[sheet]["DataInizio"] < max_date) + + if not self.df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data inizio in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO} nel foglio {sheet_num+1}" + ) + with expndr: + st.info("Tabella con errori riscontrati per data inizio in riferimento ad anno di riferimento") + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), + f"errInizioAnnoRiferimento{sheet_num}", + ) + # Set 'errInizioAnnoRiferimento' flag to True for rows with 'DataInizio' outside the range + self.df[sheet].loc[~condizione, "errInizioAnnoRiferimento"] = True + + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # + + def errFineAnnoRiferimento(self): + """ + This method checks if there are errors in the data related to the reference year. + + Returns: + None + """ + # iterate through two sheets + for sheet_index in range(2): + sheet_name = f"sheet{sheet_index}" + # find all rows where the end date is earlier than the reference date + condition = self.df[sheet_name]["DataFine"] < pd.to_datetime( + self.COSTANTI["datafine"], format="%d.%m.%Y" + ) + # invert the condition + if not self.df[sheet_name][~condition].empty: + # create a collapsible expander to show the errors + expander = st.expander(f"Trovati errori per data fine in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO}") + with expander: + st.info("Tabella con errori riscontrati per data fine in riferimento ad anno di riferimento") + # create a table to show the errors + interface.make_grid( + self.df[sheet_name][~condition].sort_values(by=["Cognome"]), + f"error_end_date_reference_year_{sheet_index}", + ) + # set a flag for rows that contain errors + self.df[sheet_name].loc[~condition, "error_end_date_reference_year"] = True + + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + + + + def errOre666(self): + """ + Check for errors in the "Delibera666" column of the "sheet1" sheet and set the "errOre666" flag to True + if there are any errors. + + Returns: + None + """ + sheet = "sheet1" + condizione = self.df[sheet]["delibera666"] > 0 + + if not self.df[sheet][~condizione].empty: + expndr = st.expander("Trovati errori per valori in Delibera 666") + + with expndr: + st.info("Tabella con errori riscontrati per delibera 666") + interface.make_grid(self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errOre666xxx") + + # set "errOre666" flag to True + self.df[sheet].loc[~condizione, "errOre666"] = True + + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre666", + + def errOre543DataInizio(self): + """ + Find errors in sheet1 where both the start date is after a certain date and the value in column "delibera543" is greater than 0. + """ + sheet = "sheet1" + # Create conditions to check for errors + condition1 = self.df[sheet]["DataInizio"] > pd.to_datetime(self.COSTANTI["datainizio543"], format="%d.%m.%Y") + condition2 = self.df[sheet]["delibera543"] > 0 + # Combine conditions with an AND operator + condition = condition1 & condition2 + # Check if there are any errors + if not self.df[sheet][condition].empty: + # Create an expander to show the errors + with st.expander("Trovati errori inserimento post Notbetreuung"): + # Show a table with the errors + st.info("Tabella con errori inserimento post Notbetreuung") + interface.make_grid(self.df[sheet][condition].sort_values(by=["Cognome"]), "errOre543DataInizioxxx") + # Set a boolean flag to indicate that there are errors + self.df[sheet].loc[condition, "errOre543DataInizio"] = True + + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataInizio", + + def errOre543DataFine(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["DataFine"] < pd.to_datetime( + self.COSTANTI["datafine543"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori fine prima di lockdown") + with expndr: + st.info("Tabella con errori fine prima di lockdown") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataFinexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOre543DataFine"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataFine", + + def errComuneProvenienza(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["ComuneProvenienza"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento comune provenienza per utente comunale" + ) + with expndr: + st.info( + "Tabella con valori mancanti per comune di proivenienza per utente comunale" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errComuneProvenienzaxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errComuneProvenienza"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errComuneProvenienza", + + def errCompilazione666(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera666"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 666 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 666 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione666xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione666"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione666", + + def errCompilazione543(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera543"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 543 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 543 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione543xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione543"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione543", + + def errCompilazioneEntrate(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["Entrate"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento entrate per utente comunale") + with expndr: + st.info("Tabella con valori mancanti per entrate per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazioneEntratexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazioneEntrate"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazioneEntrate", + + def errDataInizioAnnoRiferimento(self): + sheet = "sheet0" + condizione = self.df[sheet]["DataInizio"].dt.year >= int(self.ANNO_RIFERIMENTO) + + if not self.df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori anno inizio utenti precedenti (foglio 0) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + f"Tabella con valori erratti per anno inizio utenti precedenti (foglio 1) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioAnnoRiferimentoxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errDataInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errDataInizioAnnoRiferimento", + + def errOccorrenzeBambino(self): + """Identify occurrences where a child is enrolled in multiple facilities on the same start date. + + Returns: + - None + """ + # Select sheet 0 + sheet = "sheet0" + # Define conditions for errors + condition1 = self.df[sheet].groupby("Cognome")["DataInizio"].transform("nunique") == 1 + condition2 = self.df[sheet].groupby("Cognome")["Ente"].transform("nunique") > 1 + # Combine conditions + condition = condition1 & condition2 + # If there are errors, display them in a Streamlit expander + if not self.df[sheet][condition].empty: + expander = st.expander( + "Trovati errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + with expander: + st.info("Tabella con errori occorrenze bambino in diverse strutture per stessa data inizio") + interface.make_grid( + self.df[sheet][condition].sort_values(by=["Cognome"]), + "errOccorrenzeBambinoxxx", + ) + # Set boolean flag for errors + self.df[sheet].loc[condition, "errOccorrenzeBambino"] = True + + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + +class caricaEtControlla(): + + + dfout = {} + # siccome dobbiamo caricare excel con 2 sheet + dfout["sheet0"] = None + dfout["sheet1"] = None + + def __init__(self, interface, dizionario): + self.flag = 0 + self.df = {} # meglio metterlo fuori da __init__ ? + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.DIZIONARIO = valori.DIZIONARIO + interface.STATUS.info("Sono stati caricati " + str(len(self.filelist)) + " files") + self.carica_dati() + + def carica_dati(self): + + with interface.TAB1: + if interface.DEBUGGENERAL: st.write("entrato carica_dati") + for file in self.filelist: + try: # carica tutti i file della lista + interface.STATUS2.info(file.name + " caricato") + df1 = pd.read_excel(file, 0) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 0 + df2 = pd.read_excel(file, 1) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 1 + self.df["sheet0"] = df1 + self.df["sheet1"] = df2 + except ValueError as errore_riscontrato: + st.error( + file.name + + " non è un file Excel. Errore riscontrato: " + + str(errore_riscontrato) + ) + if interface.TOLLERANZAZERO: st.stop() + continue # se errore passiamo al prossimo file + #st.write(df1) + #st.write(df2) + try: # inizia la preparazione dei dati + interface.STATUS2.info(f"{file.name} elaborato") + self.df = self.prepare_data(self.df, file.name) + except ValueError as errore_riscontrato: + st.error(f"{str(file.name)} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione. Errore: {str(errore_riscontrato)}") + #st.warning(f"Probabilmente e' stato scelto un anno riferimento sbagliato ({self.ANNO_RIFERIMENTO}) mentre il file contiene l'anno {anno_estratto}, quindi il file caricato non e' strutturato come previsto per l'anno scelto") + if interface.TOLLERANZAZERO: st.stop() + continue # se errore passiamo al prossimo file + try: + # se dfout-foglio-0 non esiste lo creiamo + if self.dfout["sheet0"] is None: + self.dfout["sheet0"] = pd.DataFrame(columns=self.df["sheet0"].columns) + self.dfout["sheet0"] = self.df["sheet0"].copy() + del self.df["sheet0"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet0"] = pd.concat([self.dfout["sheet0"], self.df["sheet0"]]) + del self.df["sheet0"] + # se dfout-foglio-1 non esiste lo creiamo + if self.dfout["sheet1"] is None: + self.dfout["sheet1"] = pd.DataFrame(columns=self.df["sheet1"].columns) + self.dfout["sheet1"] = self.df["sheet1"].copy() + del self.df["sheet1"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet1"] = pd.concat([self.dfout["sheet1"], self.df["sheet1"]]) + del self.df["sheet1"] + except Exception as e: + st.error(f"Errore riscontrato durante il caricamento: {e}") + if interface.TOLLERANZAZERO: st.stop() + continue + #st.write(self.dfout["sheet1"]) + # ora sono tutti concatenati e possiamo restituire il dataframe + # condizione soddisfatta soltanto se entrambi i sheet non sono vuoti + if not self.dfout["sheet0"].empty and not self.dfout["sheet1"].empty: + interface.STATUS2.success( + "Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + if interface.DEBUGGENERAL: st.write(self.dfout["sheet0"]), st.write(self.dfout["sheet1"]) + + + + def prepare_data(self, df, file_name): + if interface.DEBUGGENERAL: st.write("elaboro " + file_name) + # togliamo le colonne inutili e definiamo nomi colonne + df["sheet0"] = df["sheet0"].drop(["Unnamed: 6", "Unnamed: 7"], axis=1) + df["sheet0"].columns = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["colonne0"] + + + + try: + anno_estratto = df["sheet1"].iloc[self.DIZIONARIO[self.ANNO_RIFERIMENTO]["indirizzoAnno_1"]] + anno_estratto = anno_estratto[self.DIZIONARIO[self.ANNO_RIFERIMENTO]["indirizzoAnno_2"]] + if interface.DEBUGGENERAL: st.write(f"anno estratto: {anno_estratto}") + except Exception as e: + st.error(f"Riscontrato un errore critico ({e}) - impossibile proseguire.") + st.error("CONTROLLARE CORRETTEZZA ANNO RIFERIMENTO!") + st.info("L'elaborazione e' stata interrotta") + st.stop() + if interface.DEBUGGENERAL: st.write(f"anno estratto: {anno_estratto}") + if str(anno_estratto) != str(self.ANNO_RIFERIMENTO): + st.warning(f"ATTENZIONE: l'anno contenuto nel file '{file_name}' ({anno_estratto}) non corrisponde all'anno di riferimento selezionato ({self.ANNO_RIFERIMENTO})!") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.info("L'elaborazione e' stata interrotta") + st.stop() + #return df + # può capitare che i colleghi scrivano nelle colonne a fianco di quelle che ci interessano + # e quindi eliminiamo le colonne oltre la decima (per anni 2019, 2020) + # e oltre la nona per anno 2021 + # cfr. DIZIONARIO + try: + dropAfterColumn = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["dropAfterColumn"] # la colonna dopo la quale eliminiamo le colonne + df["sheet1"] = df["sheet1"].drop(df["sheet1"].iloc[:, dropAfterColumn:], axis=1) + df["sheet1"].columns = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["colonne1"] + except Exception as e: + st.error(f"Non e' stato possibile elaborare il file '{file_name}'") + st.error(f"Probabilmente e' stato scelto un anno riferimento sbagliato ({self.ANNO_RIFERIMENTO}) mentre il file contiene l'anno {anno_estratto}, quindi il file caricato non e' strutturato come previsto per l'anno scelto") + st.error(f"Errore riscontrato durante l'elaborazione: {e}") + if interface.TOLLERANZAZERO: st.stop() + return + + df = self.make_bool_columns(df) + + for a in (0, 1): + # ciclo da foglio 0 a foglio 1 + sheet = "sheet" + str(a) + + # estrazione nome microstruttura + microstruttura = df[sheet].iloc[1] + microstruttura = microstruttura[1] + if interface.DEBUGGENERAL: st.write("microstruttura = "+ str(microstruttura)) + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(microstruttura, str) + + if not res: + st.error( + f"Manca informazione MICROSTRUTTURA nel foglio {a+1} nel file --> {file_name}" + ) + microstruttura = "assente" + # settiamo flag bool + df[sheet]["dataErrMicrostruttura"] = True + if interface.TOLLERANZAZERO: st.stop() + + # dal 2022 in poi non estraiamo piu' l'ente dal foglio ma dalla descrizione della microstruttura + if self.DIZIONARIO[self.ANNO_RIFERIMENTO]["leggiente"] == 'yes': + # estrazione nome ente + ente = df[sheet].iloc[2] + ente = ente[1] + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(ente, str) + if not res: + st.error(f"Manca informazione GESTORE nel foglio {a+1} nel file --> {file_name}") + ente = "assente" + # settiamo flag bool + df[sheet]["dataErrGestore"] = True + if interface.TOLLERANZAZERO: st.stop() + elif self.DIZIONARIO[self.ANNO_RIFERIMENTO]["leggiente"] == 'no': + ente = microstruttura.rsplit(',',1) + if len(ente) > 1: + ente = ente[1].strip() + else: + ente = ente.strip() + + # inseriamo microstruttura ed ente nel df per foglio elaborato + df[sheet].insert(0, "Microstruttura", microstruttura) + df[sheet].insert(0, "Ente", ente) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df[sheet].insert(0, "filename", file_name) + + # togliamo le prime 6 righe perché non servono più + df[sheet] = df[sheet].drop(labels=range(0, 6), axis=0) + + # selezioniamo soltanto record con un valore nel campo cognome + validi = df[sheet]["Cognome"].notna() + df[sheet] = df[sheet][validi] + + # i dati possono contenere valori data invalidi + # siccome trattiamo i dati in un df e definiamo la colonna come *datetime64* + # dobbiamo intercettare le date invalide + conditionInizio = pd.to_datetime(df[sheet]["DataInizio"], errors="coerce", dayfirst=True).isnull() + conditionFine = pd.to_datetime(df[sheet]["DataFine"], errors="coerce", dayfirst=True).isnull() + condition = conditionInizio | conditionFine + + # controlliamo se ci sono date invalide in dataFine e dataInizio + if not df[sheet][condition].empty: + expndr = st.expander(f"Trovati {len(df[sheet][condition])} errori formato data in foglio {a+1} del file --> {file_name}") + with expndr: + st.info("Errori nel formato della data inizio o data fine") + interface.make_grid( + df[sheet][condition].sort_values(by=["Cognome"]), + "errformatodate" + sheet + file_name, + ) + # settiamo la colonna bool + df[sheet].loc[condition, "errData"] = True + + # se restituiamo con la data invalida crea problemi in seguito + # quindi visto che abbiamo segnalato l'errore + # creiamo il df pulito + df[sheet] = df[sheet][~condition] + + # infine definiamo le colonne data come data + # tolto il formato perche' e' meglio non forzare il formato + + df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + df[sheet]["DataFine"] = pd.to_datetime(df[sheet]["DataFine"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + #df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], format="%d.%m.%Y") + # sostituiamo valori nulli nella colonna nome con "manca nome" + df[sheet]['Nome'] = df[sheet]['Nome'].replace(np.nan,'Manca Nome') + + + + return df + + + def make_bool_columns(self, df): + """Add boolean columns for each error/control defined in ERRORDICT. + + Args: + - df: a pandas DataFrame representing a table + + Returns: + - a pandas DataFrame representing the updated table + """ + # Loop through two sheets + for a in range(2): + sheet = f"sheet{a}" + # Loop through error dictionary items + for chiave_errore, value in self.DIZIONARIO[self.ANNO_RIFERIMENTO]["ERRORDICT"].items(): + # Convert column to boolean and add to sheet + df[sheet][chiave_errore] = np.nan + df[sheet][chiave_errore] = df[sheet][chiave_errore].astype(bool) + + return df + + def get_dfout(self): + dfout = self.dfout + return dfout + +if __name__ == "__main__": + flag = 0 + valori = valoriEtErrori() + interface = make_interface(valori.DIZIONARIO) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + caricaEtControlla(interface, valori.DIZIONARIO) + dfcompleto = caricaEtControlla.dfout + + if interface.DEBUGGENERAL: st.write(dfcompleto) + + errori = trova_errori(valori.DIZIONARIO, interface, dfcompleto) + #st.stop() + + #interface.make_tabs() + + + diff --git a/pages/03_Statistische Daten.py.off b/pages/03_Statistische Daten.py.off new file mode 100644 index 0000000000000000000000000000000000000000..1989c14f5bba81347d9aafdee768dd4f2ec323ef --- /dev/null +++ b/pages/03_Statistische Daten.py.off @@ -0,0 +1,252 @@ +import pandas as pd +import numpy as np +import streamlit as st +import openpyxl + +st.set_page_config(page_title="Statistische Daten", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Statistische Daten (v. 0.6-2023)") +#st.sidebar.write(' ') +#st.sidebar.write(' ') +#st.sidebar.image("FA.jpg") + +SHEETNAMES = ['Hinweise-indicazioni','Kitas','Kitas Gemeinden','Tagesmütter'] + +class MakeInterface(): + + def __init__(self): + self.make_sidebar() + self.get_file_list() # spostiamo nel form? + self.make_form() + #st.write(filelist) + + def make_sidebar(self): + st.sidebar.info("Controlli") + + def get_file_list(self): + self.uploaded_files = st.file_uploader("Scegliere i file da elaborare", accept_multiple_files=True) + #st.write(self.filelist) + + def make_form(self): + frm1 = st.form("Selezione", clear_on_submit = False) + with frm1: + self.submit1 = frm1.form_submit_button("Iniziare elaborazione") + + def download_excel_file(self): + file_da_scaricare = "output.xlsx" + with open(file_da_scaricare, 'rb') as f: + file_bytes = f.read() + st.sidebar.download_button( + label = "Download complessivo", + data = file_bytes, + file_name = "output.xlsx", + mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + + +class ExcelDataProcessor(): + """ + A class that takes a list of Excel files as input and processes them into a single Pandas DataFrame + """ + + def __init__(self, files): + """ + Constructor method to initialize the class with input files list + """ + self.files = files + self.df_kitas = pd.DataFrame() + self.df_kitas_gemeinden = pd.DataFrame() + self.df_tagesmütter = pd.DataFrame() + self.df_hinweise = pd.DataFrame() + + + def load_data(self, file): + """ + Loads Excel files + """ + + df_dict = {} + + try: + xl = pd.ExcelFile(file) + st.success(f"Caricato {file.name}") + except Exception as e: + st.error(f"Non è stato possibile caricare il file {file.name}; errore: {e}") + + for sheet_name in SHEETNAMES: + try: + df_dict[sheet_name] = xl.parse(sheet_name, header=None) + except Exception as e: + st.error(f"Errore durante lettura del file {file}, e foglio {sheet_name}, errore: {e}") + + + return df_dict + + def get_substring_after_dash(self,input_string): + #st.write(input_string) + parts = input_string.split(" - ") + if len(parts) > 1: + return parts[0], parts[1] + else: + return input_string, " " + + + def prepare_data(self, df_dict): + + # azioni da applicare a tutti i sheet + for k in df_dict.keys(): + + if k == "Hinweise-indicazioni": + # estrazione nome ente e anno dal primo foglio + ente = df_dict[k][1][0] + anno = df_dict[k][2][0].astype(int) + if anno == '2023': + codice_ente = df_dict[k][3][0] + + #st.warning(ente) + #st.warning(anno) + #st.warning(codice_ente) + + # non serve piu' e quindi lo buttiamo + #del df_dict[k] + continue + + #st.warning(k) + #le prime 6 righe sono inutili + df_dict[k].drop(df_dict[k].index[:6], inplace = True) + #st.write(df_dict[k]) + # elimiamo la 6sta e 7ma riga perche' non teniamo i nomi italiani + df_dict[k].drop(df_dict[k].index[1:2], inplace=True) + #st.write(df_dict[k]) + + # la riga 0 diventa header, e poi la eliminiamo + df_dict[k] = df_dict[k].rename(columns=lambda x: df_dict[k].iloc[0][x]) + + # il metodo di cui sotto da un errore json quando cerchiamo di accedere al dataframe + #df_dict[k].columns = df_dict[k].iloc[0] + + # eliminiamo la prima riga che ora non serve piu' + df_dict[k].drop(df_dict[k].index[0], inplace=True) + + # leggiamo la prima riga per verificare l'anno + # DA FARE!!!! + # intanto eliminiamo la riga con le date e con l'anno + df_dict[k].drop(df_dict[k].index[0], inplace=True) + + # togliamo il ritorno capo '\n' dai nomi delle colonne + df_dict[k].columns = df_dict[k].columns.str.replace('\n',' ') + + # sostituiamo i NaN con zero + df_dict[k] = df_dict[k].fillna(0) + + if k in ["Kitas Gemeinden", "Tagesmütter"]: + df_dict[k] = df_dict[k].iloc[:116] + + if k == "Kitas": + + # rinomiamo la prima colonna + df_dict[k].rename(columns={'Kindertagesstätte Microstruttura': 'Kindertagesstätte'}, inplace=True) + + # teniamo solo le righe che hanno un formato tipo "Neumarkt, Fleimstalerstraße, 41/1, Casa Bimbo" + # con tre virgole nella stringa + # creiamo una boolean mask + mask_kitas = df_dict[k]['Kindertagesstätte'].apply(lambda x: str(x).count(',') == 3) + if df_dict[k][mask_kitas].empty: + st.warning(f"Attenzione: il foglio 'Kitas' per l'ente '{ente}' non contiene valori usabili.\n\rL'elaborazione prosegue comunque.") + df_dict[k] = df_dict[k][mask_kitas] + + # estraiamo il comune dalla prima colonna e lo inseriamo come nuova colonna + df_dict[k].insert(0, "Comune", 'abc') + df_dict[k]['Comune'] = df_dict[k]['Kindertagesstätte'].str.split(',').str.get(0) + + # qui estraiamo l'eventuale frazione dopo il "-", es.: "Bruneck-IrgenFraktion" + # ma solo se non ci sono spazi intorno a "-" + # se ci sono spazi prima e dopo "-" assumiamo che si tratta di frazione + df_dict[k].insert(1, "Frazione",pd.NA) + if not df_dict[k][mask_kitas].empty: + df_dict[k]['Comune'], df_dict[k]['Frazione'] = zip(*df_dict[k]['Comune'].apply(self.get_substring_after_dash)) + else: + st.warning(f"Funzione di split comune - frazione non attivata perche' il foglio 'Kitas' per l'ente '{ente}' non contiene valori usabili\n\rL'elaborazione prosegue comunque.") + + # estraiamo il tipo Kita dalla prima colonna + df_dict[k].insert(0, "TipoKitas", 'Comunale') + #df_dict[k]['TipoKitas'] = df_dict[k]['Kindertagesstätte'].str.extract(r'\((.*?)\)').fillna('comunale') + + df_dict[k]['TipoKitas'] = df_dict[k]['Kindertagesstätte'].str.split(',', n=3).str.get(3).str.extract(r'\((.*?)\)')[0].fillna('comunale') + + + #comune = df_dict[k]["Kindertagesstätte"] + df_dict[k].rename(columns={df_dict[k].columns[4]: 'Codice Kita'}, inplace=True) + #st.write(df_dict[k]) + # aggiungiamo le colonne ente ed anno + df_dict[k].insert(0, "Ente", ente) + df_dict[k].insert(0, "Anno", anno) + if anno == '2023': + df_dict[k].insert(0, "Cod_Coop", codice_ente) + + + + + # azioni specifiche per sheet + + return df_dict + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + + dataframes_kitas = [] + dataframes_kitas_gemeinden = [] + dataframes_tagesmütter = [] + + for file in self.files: + df_dict = self.load_data(file) + df_dict = self.prepare_data(df_dict) + + dataframes_kitas.append(df_dict["Kitas"]) + dataframes_kitas_gemeinden.append(df_dict["Kitas Gemeinden"]) + dataframes_tagesmütter.append(df_dict["Tagesmütter"]) + + try: + # all loaded excel data gets concatenated in a new dataframe + df_dict["Kitas"] = pd.concat(dataframes_kitas, ignore_index=True) + #self.df_kitas = pd.concat(dataframes_kitas, ignore_index=True) + df_dict["Kitas Gemeinden"] = pd.concat(dataframes_kitas_gemeinden, ignore_index=True) + # self.df_kitas_gemeinden = pd.concat(dataframes_kitas_gemeinden, ignore_index=True) + df_dict["Tagesmütter"] = pd.concat(dataframes_tagesmütter, ignore_index=True) + # self.df_tagesmütter = pd.concat(dataframes_tagesmütter, ignore_index=True) + + except Exception as e: + st.error(f"Errore durante unione dei dataframe; errore: {e} \n\rImpossibile proseguire") + + #self.make_excel_file(df_dict) + self.crea_file_excel(df_dict) + + def crea_file_excel(self, df_dict): + writer = pd.ExcelWriter("output.xlsx", engine="xlsxwriter") + workbook = writer.book + for sheet_name in df_dict.keys(): + if sheet_name == 'Hinweise-indicazioni': + continue + worksheet = workbook.add_worksheet(sheet_name) + for col in range(df_dict[sheet_name].shape[1]): + if col == 5: + worksheet.set_column(col, col, 60) + elif col == 1: + worksheet.set_column(col, col, 30) + else: + worksheet.set_column(col, col, 20) + df_dict[sheet_name].to_excel(writer, sheet_name = sheet_name, index=False) + writer.close() + + +if __name__ == "__main__": + interface = MakeInterface() + if interface.submit1: + processor = ExcelDataProcessor(interface.uploaded_files) + processor.process_data() + interface.download_excel_file() + + + diff --git a/pages/03_Unione File Microstrutture.py.obsolete b/pages/03_Unione File Microstrutture.py.obsolete new file mode 100644 index 0000000000000000000000000000000000000000..a5b058ee2ca22fa5aad6df39e779aa6f5fd5b17d --- /dev/null +++ b/pages/03_Unione File Microstrutture.py.obsolete @@ -0,0 +1,243 @@ +import pandas as pd +import numpy as np +import streamlit as st +import openpyxl + +st.set_page_config(page_title="Statistische Daten", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Statistische Daten (v. 0.4c)") +#st.sidebar.write(' ') +#st.sidebar.write(' ') +#st.sidebar.image("FA.jpg") + +SHEETNAMES = ['Hinweise-indicazioni','Kitas','Kitas Gemeinden','Tagesmütter'] + +class MakeInterface(): + + def __init__(self): + self.make_sidebar() + self.get_file_list() # spostiamo nel form? + self.make_form() + #st.write(filelist) + + def make_sidebar(self): + st.sidebar.info("Controlli") + + def get_file_list(self): + self.uploaded_files = st.file_uploader("Scegliere i file da elaborare", accept_multiple_files=True) + #st.write(self.filelist) + + def make_form(self): + frm1 = st.form("Selezione", clear_on_submit = False) + with frm1: + self.submit1 = frm1.form_submit_button("Iniziare elaborazione") + + def download_excel_file(self): + file_da_scaricare = "output.xlsx" + with open(file_da_scaricare, 'rb') as f: + file_bytes = f.read() + st.sidebar.download_button( + label = "Download complessivo", + data = file_bytes, + file_name = "output.xlsx", + mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + + +class ExcelDataProcessor(): + """ + A class that takes a list of Excel files as input and processes them into a single Pandas DataFrame + """ + + def __init__(self, files): + """ + Constructor method to initialize the class with input files list + """ + self.files = files + self.df_kitas = pd.DataFrame() + self.df_kitas_gemeinden = pd.DataFrame() + self.df_tagesmütter = pd.DataFrame() + self.df_hinweise = pd.DataFrame() + + + def load_data(self, file): + """ + Loads Excel files + """ + + df_dict = {} + + try: + xl = pd.ExcelFile(file) + st.success(f"Caricato {file.name}") + except Exception as e: + st.error(f"Non è stato possibile caricare il file {file.name}; errore: {e}") + + for sheet_name in SHEETNAMES: + try: + df_dict[sheet_name] = xl.parse(sheet_name, header=None) + except Exception as e: + st.error(f"Errore durante lettura del file {file}, e foglio {sheet_name}, errore: {e}") + + + return df_dict + + def get_substring_after_dash(self,input_string): + #st.write(input_string) + parts = input_string.split(" - ") + if len(parts) > 1: + return parts[0], parts[1] + else: + return input_string, " " + + + def prepare_data(self, df_dict): + + # azioni da applicare a tutti i sheet + for k in df_dict.keys(): + + if k == "Hinweise-indicazioni": + # estrazione nome ente e anno dal primo foglio + ente = df_dict[k][1][0] + anno = df_dict[k][2][0].astype(int) + + # non serve piu' e quindi lo buttiamo + #del df_dict[k] + continue + + #st.warning(k) + #le prime 6 righe sono inutili + df_dict[k].drop(df_dict[k].index[:6], inplace = True) + #st.write(df_dict[k]) + # elimiamo la 6sta e 7ma riga perche' non teniamo i nomi italiani + df_dict[k].drop(df_dict[k].index[1:2], inplace=True) + #st.write(df_dict[k]) + + # la riga 0 diventa header, e poi la eliminiamo + df_dict[k] = df_dict[k].rename(columns=lambda x: df_dict[k].iloc[0][x]) + + # il metodo di cui sotto da un errore json quando cerchiamo di accedere al dataframe + #df_dict[k].columns = df_dict[k].iloc[0] + + # eliminiamo la prima riga che ora non serve piu' + df_dict[k].drop(df_dict[k].index[0], inplace=True) + + # leggiamo la prima riga per verificare l'anno + # DA FARE!!!! + # intanto eliminiamo la riga con le date e con l'anno + df_dict[k].drop(df_dict[k].index[0], inplace=True) + + # togliamo il ritorno capo '\n' dai nomi delle colonne + df_dict[k].columns = df_dict[k].columns.str.replace('\n',' ') + + # sostituiamo i NaN con zero + df_dict[k] = df_dict[k].fillna(0) + + if k in ["Kitas Gemeinden", "Tagesmütter"]: + df_dict[k] = df_dict[k].iloc[:116] + + if k == "Kitas": + + # rinomiamo la prima colonna + df_dict[k].rename(columns={'Kindertagesstätte Microstruttura': 'Kindertagesstätte'}, inplace=True) + + # teniamo solo le righe che hanno un formato tipo "Neumarkt, Fleimstalerstraße, 41/1, Casa Bimbo" + # con tre virgole nella stringa + # creiamo una boolean mask + mask_kitas = df_dict[k]['Kindertagesstätte'].apply(lambda x: str(x).count(',') == 3) + if df_dict[k][mask_kitas].empty: + st.warning(f"Attenzione: il foglio 'Kitas' per l'ente '{ente}' non contiene valori usabili.\n\rL'elaborazione prosegue comunque.") + df_dict[k] = df_dict[k][mask_kitas] + + # estraiamo il comune dalla prima colonna e lo inseriamo come nuova colonna + df_dict[k].insert(0, "Comune", 'abc') + df_dict[k]['Comune'] = df_dict[k]['Kindertagesstätte'].str.split(',').str.get(0) + + # qui estraiamo l'eventuale frazione dopo il "-", es.: "Bruneck-IrgenFraktion" + # ma solo se non ci sono spazi intorno a "-" + # se ci sono spazi prima e dopo "-" assumiamo che si tratta di frazione + df_dict[k].insert(1, "Frazione",pd.NA) + if not df_dict[k][mask_kitas].empty: + df_dict[k]['Comune'], df_dict[k]['Frazione'] = zip(*df_dict[k]['Comune'].apply(self.get_substring_after_dash)) + else: + st.warning(f"Funzione di split comune - frazione non attivata perche' il foglio 'Kitas' per l'ente '{ente}' non contiene valori usabili\n\rL'elaborazione prosegue comunque.") + + # estraiamo il tipo Kita dalla prima colonna + df_dict[k].insert(0, "TipoKitas", 'Comunale') + #df_dict[k]['TipoKitas'] = df_dict[k]['Kindertagesstätte'].str.extract(r'\((.*?)\)').fillna('comunale') + + df_dict[k]['TipoKitas'] = df_dict[k]['Kindertagesstätte'].str.split(',', n=3).str.get(3).str.extract(r'\((.*?)\)')[0].fillna('comunale') + + + #comune = df_dict[k]["Kindertagesstätte"] + + # aggiungiamo le colonne ente ed anno + df_dict[k].insert(0, "Ente", ente) + df_dict[k].insert(0, "Anno", anno) + + + + + # azioni specifiche per sheet + + return df_dict + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + + dataframes_kitas = [] + dataframes_kitas_gemeinden = [] + dataframes_tagesmütter = [] + + for file in self.files: + df_dict = self.load_data(file) + df_dict = self.prepare_data(df_dict) + + dataframes_kitas.append(df_dict["Kitas"]) + dataframes_kitas_gemeinden.append(df_dict["Kitas Gemeinden"]) + dataframes_tagesmütter.append(df_dict["Tagesmütter"]) + + try: + # all loaded excel data gets concatenated in a new dataframe + df_dict["Kitas"] = pd.concat(dataframes_kitas, ignore_index=True) + #self.df_kitas = pd.concat(dataframes_kitas, ignore_index=True) + df_dict["Kitas Gemeinden"] = pd.concat(dataframes_kitas_gemeinden, ignore_index=True) + # self.df_kitas_gemeinden = pd.concat(dataframes_kitas_gemeinden, ignore_index=True) + df_dict["Tagesmütter"] = pd.concat(dataframes_tagesmütter, ignore_index=True) + # self.df_tagesmütter = pd.concat(dataframes_tagesmütter, ignore_index=True) + + except Exception as e: + st.error(f"Errore durante unione dei dataframe; errore: {e} \n\rImpossibile proseguire") + + #self.make_excel_file(df_dict) + self.crea_file_excel(df_dict) + + def crea_file_excel(self, df_dict): + writer = pd.ExcelWriter("output.xlsx", engine="xlsxwriter") + workbook = writer.book + for sheet_name in df_dict.keys(): + if sheet_name == 'Hinweise-indicazioni': + continue + worksheet = workbook.add_worksheet(sheet_name) + for col in range(df_dict[sheet_name].shape[1]): + if col == 5: + worksheet.set_column(col, col, 60) + elif col == 1: + worksheet.set_column(col, col, 30) + else: + worksheet.set_column(col, col, 20) + df_dict[sheet_name].to_excel(writer, sheet_name = sheet_name, index=False) + writer.close() + + +if __name__ == "__main__": + interface = MakeInterface() + if interface.submit1: + processor = ExcelDataProcessor(interface.uploaded_files) + processor.process_data() + interface.download_excel_file() + + + diff --git "a/pages/04_BI_Antra\314\210ge_und_Abrechnungen.py.off" "b/pages/04_BI_Antra\314\210ge_und_Abrechnungen.py.off" new file mode 100644 index 0000000000000000000000000000000000000000..5ea3ff46e1383059e9098e71fd9cd43f3e676bfa --- /dev/null +++ "b/pages/04_BI_Antra\314\210ge_und_Abrechnungen.py.off" @@ -0,0 +1,469 @@ +from ast import Pass +from zlib import DEF_BUF_SIZE +import pandas as pd +import streamlit as st +import streamlit as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +import os +from openpyxl import load_workbook +import numpy as np + + +st.set_page_config(page_title="BI Anträge und Abrechnungen", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Unione file Excel microstrutture (v. 0.99)") + +SHEETNAMES = ['LK_Comuni','LK_Kita','LK_Coop'] +dict_anagrafica = {} + +class MakeInterface(): + + def __init__(self): + self.make_sidebar() + self.get_file_list() # spostiamo nel form? + self.make_form() + #st.write(filelist) + def make_sidebar(self): + st.sidebar.info("Controlli") + + def get_file_list(self): + self.uploaded_files = st.file_uploader("Scegliere i file da elaborare", accept_multiple_files=True) + #st.write(self.filelist) + def make_form(self): + frm1 = st.form("Selezione", clear_on_submit = False) + with frm1: + self.submit1 = frm1.form_submit_button("Iniziare elaborazione") + + def download_excel_file(self): + file_da_scaricare = "output.xlsx" + with open(file_da_scaricare, 'rb') as f: + file_bytes = f.read() + st.sidebar.download_button( + label = "Download complessivo", + data = file_bytes, + file_name = "output.xlsx", + mime='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + + +class ExcelDataProcessor(): + """ + A class that takes a list of Excel files as input and processes them into a single Pandas DataFrame + """ + + def __init__(self, files, df_dict): + """ + Constructor method to initialize the class with input files list + """ + self.files = files + self.df_dict_anagrafica = df_dict + self.df_completo = pd.DataFrame() + + def is_xlsx(self,filename): + + if not filename.name.endswith('.xlsx'): # check file extension + return False + + try: + load_workbook(filename) # try to open with openpyxl + except Exception: + return False + + return True + + def load_data(self, file): + try: + df = pd.read_excel(file, header = None) + except Exception as e_rror: + st.error(f"Non e' stato possibile caricare il file {file.name}; errore: {e_rror}") + + return df + + def check_integrity(self, df): + + if df[24][0] == 217: + st.success("Trovato valore di controllo '217' dove si deve trovare - continuo l'elaborazione...") + else: + st.error("Valore di controllo '217' non presente dove dovrebbe\n\rIl file non verrà caricato") + return None + + if df[25][0] == "DomandaKITA": + st.success("Trovato valore di controllo 'DomandaKITA' dove si deve trovare - continuo l'elaborazione...") + else: + st.error("Valore di controllo 'DomandaKITA' non presente dove dovrebbe\n\rIl file non verrà caricato") + return None + + return df + + def check_codes_statici(self, df): + + # qui controlliamo i codici che occorrono in cima ai fogli di lavoro + # vale a dire che occorrono solo una volta + + ente = df[0][3] + codice_ente = str(df[8][3]) + #st.info(codice_ente) + if not codice_ente.startswith("COOP_"): + st.error("Valore di codice ente non presente. Il file non verrà caricato") + st.write("") + st.write("") + return pd.DataFrame + + condizione = self.df_dict_anagrafica["LK_Coop"]["COOP_CODE"] == codice_ente + ente_estratto_da_dizionario = self.df_dict_anagrafica["LK_Coop"].loc[condizione, 'COOP_DESC_D'].values[0] + + if ente.strip() == ente_estratto_da_dizionario.strip(): + st.success("L'ente riportato e il codice sono stati trovati nel dizionario e corrispondono - continuo l'elaborazione...") + else: + st.error("L'ente riportato e il codice non sono stati trovati nel dizionario. Il file non verrà caricato") + return pd.DataFrame + + anno = df[2][3] + st.success(f"Trovato anno {anno}") + df.insert(0,"Anno", anno) + df.insert(1,"Ente", ente) + + return df + + def check_codes_kita(self, df, c1, c2, c3): + # qui controlliamo i codici che occorrono nelle righe dove si trovano i dati veri e propri + # si tratta di Kita_Code (codice kita, colonna I nel Excel) + c1.info("Controllo codice Kita nei dati...") + c2.info("------------->") + df_kitax = self.df_dict_anagrafica["LK_Kita"][["KITA_FULL_NAME_I", "KITA_FULL_NAME_D", "KITA_CODE"]] + merged_df = pd.merge(df, df_kitax, left_on=8, right_on="KITA_CODE", how="inner") + #st.write(df) + merged_df_I = merged_df[merged_df[1] == merged_df['KITA_FULL_NAME_I']] + merged_df_D = merged_df[merged_df[1] == merged_df['KITA_FULL_NAME_D']] + + merged_df = pd.concat([merged_df_I, merged_df_D], axis=0) + #st.write(merged_df) + #st.write(pd.concat([merged_df.iloc[:, :12], merged_df['KITA_FULL_NAME_D']], axis=1)) + if merged_df.empty: + c3.error("Non OK!") + c1.error("Nessun codice KITA trovato oppure nessuno e' valido - l'elaborazione del file non continua") + c2.info("------------->") + c3.info("Passo al prossimo file (se esiste)") + return pd.concat([merged_df.iloc[:, :12], merged_df['KITA_FULL_NAME_D']], axis=1) # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + if len(merged_df) != len(df): + c3.warning("Riscontrati problemi") + c1.warning(f"Non vengono usate tutte le righe poiche' alcune non contengono il codice KITA. Righe originali {len(df)}, righe usate {len(merged_df)}") + c2.info("------------->") + c3.success("OK!") + return pd.concat([merged_df.iloc[:, :12], merged_df['KITA_FULL_NAME_D']], axis=1) + + def check_codes_traegergemeinde(self, df, c1, c2, c3): + # qui controlliamo i codici che occorrono nelle righe dove si trovano i dati veri e propri + # si tratta di Com_Code (codice comune, colonna H nel Excel) + c1.info("Controllo codice COMUNE nei dati...") + c2.info("------------->") + #st.write(df) + + df_comunix = self.df_dict_anagrafica["LK_Comuni"][["Com_Desc_I", "Com_Desc_D", "Com_Code", "Com_Flag_Active"]] + + #st.write(df_comunix) + merged_df = pd.merge(df, df_comunix, left_on=7, right_on="Com_Code", how="inner") + #st.write('traegergem') + #st.write(merged_df) + #st.write(pd.concat([merged_df.iloc[:, :12], merged_df[['KITA_FULL_NAME_D','Com_Desc_D']]], axis=1)) + #merged_df_I = merged_df[merged_df[0] == merged_df['Com_Desc_I']] + #st.write(merged_df_I) + #merged_df_D = merged_df[merged_df[0] == merged_df['Com_Desc_D']] + #st.write(merged_df_D) + #merged_df = pd.concat([merged_df_I, merged_df_D], axis=0) + #st.write(merged_df) + if merged_df.empty: + c3.error("Non OK!") + c1.error("Nessun codice COMUNE trovato oppure nessuno e' valido - l'elaborazione del file non continua") + c2.info("------------->") + c3.info("Passo al prossimo controllo") + return df # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + if len(merged_df)!= len(df): + c3.warning("Riscontrati problemi") + c1.warning(f"Non vengono usate tutte le righe poiche' alcune non contengono il codice COMUNE. Righe originali {len(df)}, righe usate {len(merged_df)}") + c2.info("------------->") + c3.success("OK!") + # Com_Desc_D diventa 'Com_Desc_D_x e poi il comune dell'ente, Gemeinde + # forse il caso di rinominare gia' qui?? + return pd.concat([merged_df.iloc[:, :12], merged_df[['KITA_FULL_NAME_D','Com_Desc_D']]], axis=1) + #return merged_df.iloc[:, :12] + + def check_codes_herkunftgemeinde(self, df, c1, c2, c3): + # qui controlliamo i codici che occorrono nelle righe dove si trovano i dati veri e propri + # si tratta di Com_Code (codice comune, colonna H nel Excel) + c1.info("Controllo codice COMUNE di origine bimbo nei dati...") + c2.info("------------->") + df_comunix = self.df_dict_anagrafica["LK_Comuni"][["Com_Desc_I", "Com_Desc_D", "Com_Code", "Com_Flag_Active"]] + merged_df = pd.merge(df, df_comunix, left_on=9, right_on="Com_Code", how="inner") + merged_df.drop('Com_Desc_I', axis=1, inplace=True) + + + #st.write('herkunftgem') + #st.write(merged_df) + # merged_df_I = merged_df[merged_df[3] == merged_df['Com_Desc_I']] + # merged_df_D = merged_df[merged_df[3] == merged_df['Com_Desc_D']] + + # merged_df = pd.concat([merged_df_I, merged_df_D], axis=0) + + if merged_df.empty: + c3.error("Non OK!") + c1.error("Nessun codice COMUNE trovato per comune origine del bimbo oppure nessuno e' valido - l'elaborazione del file non continua") + c2.info("------------->") + c3.info("Passo al prossimo controllo") + return df #pd.concat([merged_df.iloc[:, :12], merged_df['KITA_FULL_NAME_D']], axis=1) # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + if len(merged_df)!= len(df): + c3.warning("Riscontrati problemi") + c1.warning(f"Non vengono usate tutte le righe poiche' alcune non contengono il codice COMUNE per il comune di origine del bimbo. Righe originali {len(df)}, righe usate {len(merged_df)}") + c2.info("------------->") + c3.success("OK!") + # 'Com_Desc_D_x diventa poi il comune dell'ente, 'Com_Desc_D_y il comune di provenienza, Herkunftsgemeinde + # il rename succede in def process_data(self) + return pd.concat([merged_df.iloc[:, :12], merged_df[['KITA_FULL_NAME_D','Com_Desc_D_x','Com_Desc_D_y']]], axis=1) + + def check_valori_orari(self,df, c1, c2, c3): + #st.write("enter4") + #st.write(df) + # qui controlliamo i valori che occorrono nelle righe dove si trovano i dati veri e propri + # controlliamo che siano compresi tra 0.1 e 1.3 (inclusi entrambi) + c1.info("Controllo i valori riportati per il costo orario...") + c2.info("------------->") + mask = (df[2] >= 0.1) & (df[2] <= 1.3) + # e' TRUE se tutti i valori sono compresi tra 0.1 e 1.3 + all_values_in_range = mask.all() + df_filtered = df[mask] + if df_filtered.empty: + c3.error("Non OK!") + c1.error("Nessun valore riportato nel costo orario oppure nessuno e' compreso tra 0.1 e 1.3") + c2.info("------------->") + c3.info("Passo al prossimo file (se esiste)") + return df_filtered # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + if not all_values_in_range: + c3.warning("Riscontrati problemi") + c1.warning(f"Non tutti i valori sono compresi tra 0.1 e 1.3. Righe originali {len(df)}, righe usate {len(df_filtered)}") + c2.info("------------->") + + c3.success("OK!") + + return df_filtered # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + def check_valori_assistenza(self, df, c1, c2, c3): + c1.info("Controllo i valori riportati per il costo assistenza...") + c2.info("------------->") + df[4] = pd.to_numeric(df[4], errors='coerce') + mask = df[4] > 0 + values_are_numeric_and_positive = mask.all() + #st.write(df) + + df_filtered = df[mask] + #st.write(df_filtered) + if df_filtered.empty: + c3.error("Non OK!") + c1.error("Nessun valore riportato nel costo assistenza oppure nessuno e' positivo") + c2.info("------------->") + c3.info("Passo al prossimo file (se esiste)") + return df_filtered # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + if not values_are_numeric_and_positive: + st.write(df_filtered) + c3.warning("Riscontrati problemi") + c1.warning(f"Non tutti i valori sono positivi. Righe originali {len(df)}, righe usate {len(df_filtered)}") + c2.info("------------->") + + c3.success("OK!") + + return df_filtered # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + + def prepare_data(self, df): + #st.write("prepare data") + #st.write(df) + # facciamo una prima selezione delle righe che contengono un valore nelle prime due colonne a partire dalla riga 9 + # cosi' abbiamo una prima stima delle righe utili + c1,c2,c3 = st.columns([3,0.5,2]) + condition_0 = df.iloc[8:61, 2].notna() + filtered_df_0 = df.iloc[8:61][condition_0] + #st.write(filtered_df_0) + + # teniamo solo records che hanno un valore nelle prime 6 colonne, e nell'ottava, nona e decima colonna + condition = df.iloc[8:, :5].notnull().all(axis=1) & df.iloc[:, 7:9].notnull().any(axis=1) + filtered_df = df.loc[condition] + c1.info("Controllo della validita' dei dati contenuti") + c2.info("------------->") + + if len(filtered_df) < len(filtered_df_0): + c3.warning("Riscontrati problemi") + c1.warning(f"Non tutte le righe contengono valori usabili: sono state eliminate {len(filtered_df_0) - len(filtered_df)} righe; ne rimangono {len(filtered_df)}.") + c2.info("------------->") + if filtered_df.empty: + c3.error("Non sono rimaste righe da usare") + # c3.warning("continuo...") + #st.write(filtered_df) + + if filtered_df.empty: + + c1.error("I dati contenuti non sono strutturati in modo corretto oppure mancano dati essenziali. Impossibile proseguire") + c2.info("------------->") + c3.info("Passo al prossimo file (se esiste)") + return filtered_df # anche se vuoto lo ritorniamo perche' contiene le colonne giuste + #st.write(filtered_df) + c3.success("OK!") + return filtered_df + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + dataframes = [] + for file in self.files: + + #st.info(f"====================== CARICATO FILE {file.name.upper()} ======================") + st.markdown(f"

CARICATO FILE {file.name.upper()}

", unsafe_allow_html=True) + if not self.is_xlsx(file): + st.error(f"Il file {file.name} non è un file Excel e non verrà caricato") + continue + + df = self.load_data(file) + df = self.check_integrity(df) + df = self.check_codes_statici(df) + # fino a questo punto possono essere restituiti dataframe vuoti + if not df.empty: + + df = self.prepare_data(df) + if not df.empty: + c1,c2, c3 = st.columns([3,0.5,2]) + df = self.check_codes_kita(df, c1, c2, c3) + #st.write("returner1") + #st.write(df) + if not df.empty: + df = self.check_codes_traegergemeinde(df, c1, c2, c3) + else: + continue + #st.write("returner2") + #st.write(df) + if not df.empty: + df = self.check_codes_herkunftgemeinde(df, c1, c2, c3) + else: + continue + #st.write("returner3") + #st.write(df) + if not df.empty: + df = self.check_valori_orari(df, c1, c2, c3) + else: + continue + #st.write("returner4") + #st.write(df) + if not df.empty: + df = self.check_valori_assistenza(df, c1, c2, c3) + else: + continue + else: + continue + else: + continue + + st.success(f"Terminata elaborazione file {file.name}") + st.write("\n\n") + st.write("\n\n") + dataframes.append(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.df_completo = pd.concat(dataframes, ignore_index=True) + #st.write(self.df_completo) + self.df_completo = self.df_completo.drop(self.df_completo.columns[8], axis=1) + #st.write(self.df_completo) + self.df_completo.columns = ['Jahr','Traeger','Gemeinde','Kindertagesstaette','Betrag','Herkunftsgemeinde','Betreuungstunden','AngesuchterBeitrag','ComCode','KitaCode','ComUtCode','KITA_FULL_NAME_D','Com_Desc','Com_Desc_Prov'] + self.df_completo.drop('Kindertagesstaette', axis=1, inplace=True) + self.df_completo.drop('Gemeinde', axis=1, inplace=True) + self.df_completo.drop('Herkunftsgemeinde', axis=1, inplace=True) + self.df_completo.rename(columns={'KITA_FULL_NAME_D':'Kindertagesstaette'}, inplace=True) + self.df_completo.rename(columns={'Com_Desc':'Gemeinde'}, inplace=True) + self.df_completo.rename(columns={'Com_Desc_Prov':'Herkunftsgemeinde'}, inplace=True) + columns = list(self.df_completo.columns) + columns.remove('Kindertagesstaette') + columns.remove('Gemeinde') + columns.remove('Herkunftsgemeinde') + columns.insert(3, 'Kindertagesstaette') + columns.insert(2, 'Gemeinde') + columns.insert(5, 'Herkunftsgemeinde') + self.df_completo = self.df_completo[columns] + + except Exception as e_rror: + st.error(f"Errore durante unione dei dataframe; errore: {e_rror} \n\rImpossibile proseguire") + st.stop() + + def get_dataframe(self): + ''' + returns the dataframe + ''' + + return self.df_completo + + def download_excel_file(self, dftosave, nome_file="output.xlsx", flag=None): # questa la versione in uso + #nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + + #if flag != "casospeciale": + # dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.sidebar.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + +class HelperTools(): + + def __init__(self): + self.file_anagrafica = './BI_Antraege_Abrechungen/anagrafica_20230515_fmt_KKB.xlsx' + self.dict_anagrafica = {} + self.load_anagrafica() + + def load_anagrafica(self): + try: + xl = pd.ExcelFile(self.file_anagrafica) + st.success("Caricato file anagrafica - OK!") + except Exception as e_rror: + st.error(f"Errore durante caricamento anagrafica; errore: {e_rror}\n\rImpossibile proseguire") + st.stop() + + for sheet_name in SHEETNAMES: + #st.write(sheet_name) + try: + self.dict_anagrafica[sheet_name] = xl.parse(sheet_name) + except Exception as e_rror: + st.error(f"Errore durante lettura file anagrafica; errore: {e_rror}\n\rImpossibile proseguire") + st.stop() + + def get_anagrafica(self): + return self.dict_anagrafica + +if __name__ == "__main__": + interface = MakeInterface() + if interface.submit1: + + helper = HelperTools() + dict_anagrafica = helper.get_anagrafica() + #st.write(dict_anagrafica) + + processor = ExcelDataProcessor(interface.uploaded_files, dict_anagrafica) + processor.process_data() + df = processor.get_dataframe() + st.write("") + st.write("") + st.info("Dati finali") + st.write(df) + processor.download_excel_file(df) \ No newline at end of file diff --git a/pages/05_Listen TM.py.old b/pages/05_Listen TM.py.old new file mode 100644 index 0000000000000000000000000000000000000000..e811a4ab412e2332baf328083146cc84ef596eac --- /dev/null +++ b/pages/05_Listen TM.py.old @@ -0,0 +1,45 @@ +import pandas as pd +import streamlit as st + # cerchiamo di fare in modo che rimanga una soluzione temporanea +import os +from openpyxl import load_workbook +import numpy as np +import sys + +# ci serve per import dei oduli in comune +sys.path.insert(0, '../commontools') + +# i moduli in comune +from helpertools22 import HelperTools +from intrfc import MakeInterface + +#dc = DataCoordinates() + + +st.set_page_config(page_title="Listen Tagesmuetter", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Listen Tagesmuetter (v. 1.2)") + +SHEETNAMES = ['Elenco-Liste','LK_Comuni','LK_Diplomi','LK_Coop'] + +if __name__ == "__main__": + interface = MakeInterface() + ht = HelperTools(interface.listen_anzeigen) + if interface.submit1: + if len(interface.uploaded_files) > 6: + st.error('Es wurden mehr als 6 Excel Dateien hochgeladen') + st.error('Die Verarbeitung wird unterbrochen') + st.stop() + data_dict = ht.load_excel_files(interface.uploaded_files) + #st.write(data_dict) + #data_dict = ht.load_data(sheets) + #data_dict = ht.analyze_sheet_data(data_dict) + all_dataframes = ht.append_all_dataframes(data_dict) + ht.make_traeger_summary_excel_file(all_dataframes) + ht.make_gemeinden_summary_excel_file(all_dataframes) + + #st.write(all_dataframes) + ht.download_excel_file() + + + \ No newline at end of file diff --git a/pages/05_Listen Tagesmuetter 2024.py.off b/pages/05_Listen Tagesmuetter 2024.py.off new file mode 100644 index 0000000000000000000000000000000000000000..3a5569bf137ebf9c3d4adbdb16aca69f58141d3e --- /dev/null +++ b/pages/05_Listen Tagesmuetter 2024.py.off @@ -0,0 +1,45 @@ +import pandas as pd +import streamlit as st + # cerchiamo di fare in modo che rimanga una soluzione temporanea +import os +from openpyxl import load_workbook +import numpy as np +import sys + +# ci serve per import dei oduli in comune +sys.path.insert(0, '../commontools') + +# i moduli in comune +from helpertools22 import HelperTools +from intrfc import MakeInterface + +#dc = DataCoordinates() + + +st.set_page_config(page_title="Listen Tagesmuetter", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Listen Tagesmuetter (v. 1.21_2024)") + +SHEETNAMES = ['Elenco-Liste','LK_Comuni','LK_Diplomi','LK_Coop'] + +if __name__ == "__main__": + interface = MakeInterface() + ht = HelperTools(interface.listen_anzeigen) + if interface.submit1: + if len(interface.uploaded_files) > 6: + st.error('Es wurden mehr als 6 Excel Dateien hochgeladen') + st.error('Die Verarbeitung wird unterbrochen') + st.stop() + data_dict = ht.load_excel_files(interface.uploaded_files) + #st.write(data_dict) + #data_dict = ht.load_data(sheets) + #data_dict = ht.analyze_sheet_data(data_dict) + all_dataframes = ht.append_all_dataframes(data_dict) + ht.make_traeger_summary_excel_file(all_dataframes) + ht.make_gemeinden_summary_excel_file(all_dataframes) + + #st.write(all_dataframes) + ht.download_excel_file() + + + \ No newline at end of file diff --git a/pages/05_Listen Tagesmuetter.py.previous b/pages/05_Listen Tagesmuetter.py.previous new file mode 100644 index 0000000000000000000000000000000000000000..e811a4ab412e2332baf328083146cc84ef596eac --- /dev/null +++ b/pages/05_Listen Tagesmuetter.py.previous @@ -0,0 +1,45 @@ +import pandas as pd +import streamlit as st + # cerchiamo di fare in modo che rimanga una soluzione temporanea +import os +from openpyxl import load_workbook +import numpy as np +import sys + +# ci serve per import dei oduli in comune +sys.path.insert(0, '../commontools') + +# i moduli in comune +from helpertools22 import HelperTools +from intrfc import MakeInterface + +#dc = DataCoordinates() + + +st.set_page_config(page_title="Listen Tagesmuetter", layout="wide") +st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") +st.markdown("## Listen Tagesmuetter (v. 1.2)") + +SHEETNAMES = ['Elenco-Liste','LK_Comuni','LK_Diplomi','LK_Coop'] + +if __name__ == "__main__": + interface = MakeInterface() + ht = HelperTools(interface.listen_anzeigen) + if interface.submit1: + if len(interface.uploaded_files) > 6: + st.error('Es wurden mehr als 6 Excel Dateien hochgeladen') + st.error('Die Verarbeitung wird unterbrochen') + st.stop() + data_dict = ht.load_excel_files(interface.uploaded_files) + #st.write(data_dict) + #data_dict = ht.load_data(sheets) + #data_dict = ht.analyze_sheet_data(data_dict) + all_dataframes = ht.append_all_dataframes(data_dict) + ht.make_traeger_summary_excel_file(all_dataframes) + ht.make_gemeinden_summary_excel_file(all_dataframes) + + #st.write(all_dataframes) + ht.download_excel_file() + + + \ No newline at end of file diff --git a/pages/Betriebliche_Kitas.py.old b/pages/Betriebliche_Kitas.py.old new file mode 100644 index 0000000000000000000000000000000000000000..6223ba42f095b494bd90503029344eb909387998 --- /dev/null +++ b/pages/Betriebliche_Kitas.py.old @@ -0,0 +1,1084 @@ +from ast import Global +from calendar import c +from cmath import exp + +from os import path +from telnetlib import STATUS + +# from unicodedata import name + +import numpy as np +import pandas as pd +import datetime as dt +# import datetime as dt +import copy + +# import xlsxwriter + +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +from datetime import date + +st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="🤗" # 👽 +) + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + # "dataErrMicrostruttura": "Controllo compilazione microstruttura", + # "dataErrGestore": "Controllo compilazione gestore", + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", +} + +COSTANTI = {} +costanti_2020 = { + "datainiziomin": "01.01.2017", + "datainiziomax": "31.12.2020", + "datafine": "31.12.2023", + "datainizio543": "23.11.2020", + "datafine543": "24.02.2020", + "datafineassistenza_foglio1": "01.01.2020", + "datafineassistenza_foglio0": "01.01.2020", +} + +costanti_2019 = { + "datainiziomin": "01.01.2016", + "datainiziomax": "31.12.2019", + "datafine": "31.12.2022", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2019", + "datafineassistenza_foglio0": "01.01.2019", +} + +COSTANTI = {"2020": costanti_2020, "2019": costanti_2019} + + +def app(): + # solite cose... + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader( + "Controllo errori BETRIEBLICHE KITAS (v. 0.99.5x - Mega Shit Happens, Again)" + ) + dfout = None + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + # usiamo un avariabile globale per anno riferimento + + global ANNO_RIFERIMENTO + ANNO_RIFERIMENTO = st.selectbox( + "ANNO RIFERIMENTO", ("2019", "2020", "2021", "2022") + ) + + # scelta dei controlli + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + # le definiamo come variabili globali in modo da poterle usare ovvunque + global STATUS + STATUS = st.empty() + global STATUS2 + STATUS2 = st.empty() + + global DEBUGMODE + DEBUGMODE = st.checkbox("Debug mode per controllo sovrapposizione temporale") + + global TAB1, TAB2, TAB3, TAB4 + TAB1, TAB2, TAB3, TAB4 = st.tabs( + [ + "ERRORI INTEGRITÀ DATI", + "ERRORI NEI DATI", + "ERRORI SOVRAPPOSIZIONE TEMPORALE", + "TABELLE FINALI", + ] + ) + + # se button pigiato, allora esegui... + if flag == 1: + # with TAB1: + dfout = get_data(uploaded_files) + # dfout1, dfout2 = get_data(uploaded_files) + # if not dfout['sheet0'].empty and not dfout['sheet1'].empty: + # with TAB2: + dffinal = check_data2(dfout, checks) + with TAB4: + # st.info("") + # st.info("TABELLE FINALI") + expndr = st.expander( + "TABELLA RIASSUNTIVA ELENCO UTENTI PRECEDENTI (FOGLIO 0)" + ) + with expndr: + st.info("Tabella riassuntiva elenco utenti precedenti") + make_grid( + dffinal["sheet0"].sort_values(by=["DataInizio"]), "riassunto0" + ) + + expndr = st.expander("TABELLA RIASSUNTIVA ELENCO UTENTI (FOGLIO 1)") + with expndr: + st.info("Tabella riassuntiva elenco utenti") + make_grid( + dffinal["sheet1"].sort_values(by=["DataInizio"]), "riassunto1" + ) + + +################################# +## INIZIO CHECKS +################################# + + +def errPluriNominato(df): + + # qui scegliamo una soluzione diversa dal solito + # lavoriamo con *insiemi* + # creiamo nuovo df con nomi che hanno stessa data inizio su entrambi i fogli + df_same_data_inizio = pd.merge( + df["sheet0"], df["sheet1"], on=["Cognome", "Nome", "DataInizio"], how="inner" + ) + + # creiamo nuovo df con nomi che hanno stessa data fine su entrambi i fogli + df_same_data_fine = pd.merge( + df["sheet0"], df["sheet1"], on=["Cognome", "Nome", "DataFine"], how="inner" + ) + + # se uno dei due df non è vuoto abbiamo la condizione di errore + if not df_same_data_inizio.empty or not df_same_data_fine.empty: + expndr = st.expander( + "Trovati bambini con stessa data inizio o stessa data fine o entrambe le date uguali (in riferimento ai due fogli)" + ) + with expndr: + st.info( + "Tabella con utenti che hanno la stessa data inizio o fine o entrambi (in riferimento ai due fogli)" + ) + + # uniamo i due df con un outer join + df_same_data = pd.merge( + df_same_data_inizio, + df_same_data_fine, + on=["Cognome", "Nome"], + how="outer", + ) + + # facciamo la aggrid qui per semplicità anche se non è soluzione elegante + gridOptions = buildGrid(df_same_data) + AgGrid( + df_same_data, + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="same_data_fine_inizio", + ) + + # non definiamo le colonne bool, visto l'approccio usato + + return df + + +def errTimeSeries(df): + # strano che funziona chiamare il TAB3 qui + with TAB3: + + # st.info("") + st.info( + "SOVRAPPOSIZIONI TEMPORALI UTENTI COMUNALI E AZIENDALI - CANDIDATI PER ESCLUSIONE" + ) + # questo è il controllo più complesso, still work in progress + + # aggiungiamo la colonna *delibera666* perché dopo ci serve + df["sheet0"]["delibera666"] = 0 + + # creiamo una lista con entrambi i df + # possiamo dire quale colonne prendere dal sheet1 con la sintassi che segue + frames = [ + df["sheet0"], + df["sheet1"][ + [ + "Ente", + "Microstruttura", + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + ] + ], + ] + + # uniamo i due df - ora i contenuti di sheet0 e sheet1 sono in un unico df + result = pd.concat(frames) + result = result.drop("filename", axis=1) + # ordiniamo tutto per data inizio + result = result.sort_values(by=["DataInizio"]) + + # dobbiamo intercettare ed eliminare righe con lo stesso Cognome, Nome, Utenza, DataInizio, DataFine + # bisogna vedere se questa soluzione va bene + + result.drop_duplicates(subset=["Cognome", "Nome", "utente", "DataInizio", "DataFine"], inplace=True) + + # resettiamo l'indice in modo che inizi da 0 + result = result.reset_index() + # potrebbe servire per debug + if DEBUGMODE: + try: + result.to_excel("dataframePrimaDiAlgoritmo.xlsx") + except Exception as e: + st.error("Could not save dataframe to file, reason: " + e) + + # inizializziamo i contatori per utenti comunali e aziendali + cont_a = 0 + cont_c = 0 + + # inizializziamo le liste con le date fine incontrate durante l'iterazione sui record del df + datafineprecedenti_c = [] + datafineprecedenti_a = [] + + st.write( + "################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################" + ) + + # dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice + for ind in result.index: + # si tratta di utente comunale? + if result["utente"][ind] == "comunale": + cont_c += 1 # incrementiamo il contatore + datafineprecedenti_c.append( + str(result["DataFine"][ind]) + ) # salviamo la data fine incontrata dureante iterazione + d_c = copy.copy( + datafineprecedenti_c + ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for ( + a + ) in ( + datafineprecedenti_c + ): # loopiamo tutte le data fine incontrate precedentemente + if ( + str(result["DataInizio"][ind]) > a + ): # se incontrata una data inizio superiore a una data fine già incontrata + if DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente comunale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore comunale valore attuale = " + + str(cont_c) + ) + cont_c -= 1 # sottraiamo contatore + if DEBUGMODE: + st.write("Sottrazione --> contatore comunale = " + str(cont_c)) + d_c.remove( + a + ) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_c = copy.copy( + d_c + ) # deep copy della lista aggiornata (senza data fine "consumate") + + # si tratta di utente aziendale? + elif result["utente"][ind] == "aziendale": + cont_a += 1 # incrementiamo il contatore + datafineprecedenti_a.append( + str(result["DataFine"][ind]) + ) # salviamo la data fine incontrata dureante iterazione + d_a = copy.copy( + datafineprecedenti_a + ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for ( + a + ) in ( + datafineprecedenti_a + ): # loopiamo tutte le data fine incontrate precedentemente + if ( + str(result["DataInizio"][ind]) > a + ): # se incontrata una data inizio superiore a una data fine già incontrata + if DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente aziendale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore aziendale valore attuale = " + + str(cont_a) + ) + cont_a -= 1 # sottraiamo contatore + if DEBUGMODE: + st.write("Sottrazione --> contatore aziendale = " + str(cont_a)) + d_a.remove( + a + ) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_a = copy.copy( + d_a + ) # deep copy della lista aggiornata (senza data fine "consumate") + + if DEBUGMODE: + st.write("STATO ATTUALE CONTATORE: bimbo " + result["utente"][ind] + "\t--> " + result["Cognome"][ind] + " " + result["Nome"][ind] + " \t--> contatore comunale = " + str(cont_c) + " e contatore aziendale = " + str(cont_a)) + # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta + if ( + (cont_c >= cont_a) + and result["utente"][ind] == "comunale" + and result["DataInizio"][ind] + >= pd.to_datetime("03.10.2017", format="%d.%m.%Y") + ): + + # st.write("trovato!!!!!!!") + st.warning( + f"[*] Bimba/o {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {result['delibera666'][ind]}" + ) + cont_c -= 1 # sottraiamo contatore + if DEBUGMODE: + st.write( + "tolto bimbo: contatore comunale = " + + str(cont_c) + + " e contatore aziendale = " + + str(cont_a) + ) + st.write() + st.write( + "################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################" + ) + + return df + + +def errElencoUtenti0( + df, +): # controllo data fine assistenza minore di un certo valore, foglio 0 + sheet = "sheet0" + condizione = df[sheet]["DataFine"] < pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datafineassistenza_foglio0"], format="%d.%m.%Y" + ) + + # invertiamo la condizione + if not df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori ELENCO UTENTI PRECEDENTI per anno di riferimento {ANNO_RIFERIMENTO} sul PRIMO FOGLIO" + ) + with expndr: + st.info( + "Tabella con errori ELENCO UTENTI PRECEDENTI in riferimento ad anno di riferimento sul PRIMO FOGLIO" + ) + make_grid( + df[sheet][~condizione].sort_values(by=["Cognome"]), "errElencoUtentixxx" + ) + # settiamo flag bool + df[sheet].loc[~condizione, "errElencoUtenti0"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + # + return df + + +# def errElencoUtenti1(df): # controllo data fine assistenza minore di un certo valore, foglio 1 +# sheet = "sheet1" +# condizione = df[sheet]["DataFine"] < pd.to_datetime( +# COSTANTI[ANNO_RIFERIMENTO]["datafineassistenza_foglio1"], format="%d.%m.%Y" +# ) + +# non invertiamo la condizione +# if not df[sheet][condizione].empty: +# expndr = st.expander( +# f"Trovati errori ELENCO UTENTI per anno di riferimento {ANNO_RIFERIMENTO} sul SEC1ONDO FOGLIO" +# ) +# with expndr: +# st.info( +# "Tabella con errori ELENCO UTENTI in riferimento ad anno di riferimento sul SECONDO FOGLIO" +# ) +# make_grid(df[sheet][condizione].sort_values(by=["Cognome"]), "errElencoUtenti1xxx") +# # settiamo flag bool +# df[sheet].loc[condizione, "errElencoUtenti1"] = True +# # x = dwnld( +# # df[sheet][~condizione].sort_values(by=["Cognome"]), +# # "Scaricare tabella con errori data inizio maggiore di data fine", +# # "errInizioAnnoRiferimento", +# # +# return df + + +def errTipoKitas(df): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = df[sheet]["utente"] != "comunale" + condizione2 = df[sheet]["utente"] != "aziendale" + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori nella descrizione tipo Kitas nel foglio {a+1}" + ) + with expndr: + st.info("Errori riscontrati nella descrizione della tipologia Kitas") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errTipoKitas" + str(a), + ) + + # settiamo flag bool + df[sheet].loc[condizione, "errTipoKitas"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori tipologia Kitas", + # "errTipoKitas", + # ) + return df + + +def errDataInizioFine(df): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = df[sheet]["DataInizio"] > df[sheet]["DataFine"] + if not df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori nel rapporto data fine vs data inizio nel foglio {a+1}" + ) + with expndr: + st.info("Errori riscontrati; data inizio_maggiore data_fine") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioFine" + str(a), + ) + # settiamo flag bool + df[sheet].loc[condizione, "errDataInizioFine"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errDataInizioFine", + # ) + return df + + +def errNome(df): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = pd.isnull(df[sheet]["Nome"]) + condizione2 = pd.isnull(df[sheet]["Cognome"]) + condizione = condizione1 | condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati valori nulli per cognome o nome o entrambi nel foglio {a+1}" + ) + with expndr: + st.info("Tabella con cognome o nome o entrambi assenti") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errNome" + str(a), + ) + # settiamo flag bool + df[sheet].loc[condizione, "errNome"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errNome", + # + return df + + +def errInizioAnnoRiferimento(df): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = df[sheet]["DataInizio"] > pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datainiziomin"], format="%d.%m.%Y" + ) + condizione2 = df[sheet]["DataInizio"] < pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datainiziomax"], format="%d.%m.%Y" + ) + condizione = condizione1 & condizione2 + # invertiamo la condizione + if not df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data inizio in riferimento ad anno di riferimento {ANNO_RIFERIMENTO} nel foglio {a+1}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data inizio in riferimento ad anno di riferimento" + ) + make_grid( + df[sheet][~condizione].sort_values(by=["Cognome"]), + "errInizioAnnoRiferimento" + str(a), + ) + # settiamo flag bool + df[sheet].loc[~condizione, "errInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + # + return df + + +def errFineAnnoRiferimento(df): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = df[sheet]["DataFine"] < pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datafine"], format="%d.%m.%Y" + ) + # invertiamo la condizione + if not df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data fine in riferimento ad anno di riferimento {ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data fine in riferimento ad anno di riferimento" + ) + make_grid( + df[sheet][~condizione].sort_values(by=["Cognome"]), + "errFineAnnoRiferimento" + str(a), + ) + # settiamo flag bool + df[sheet].loc[~condizione, "errFineAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + + return df + + +def errOre666(df): + sheet = "sheet1" + condizione = df[sheet]["delibera666"] > 0 + if not df[sheet][~condizione].empty: + expndr = st.expander(f"Trovati errori per valori in Delibera 666") + with expndr: + st.info("Tabella con errori riscontrati per delibera 666") + make_grid( + df[sheet][~condizione].sort_values(by=["Cognome"]), "errOre666xxx" + ) + # settiamo flag bool + df[sheet].loc[~condizione, "errOre666"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre666", + + return df + + +def errOre543DataInizio(df): + sheet = "sheet1" + condizione1 = df[sheet]["DataInizio"] > pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datainizio543"], format="%d.%m.%Y" + ) + condizione2 = df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento post Notbetreuung") + with expndr: + st.info("Tabella con errori inserimento post Notbetreuung") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataInizioxxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errOre543DataInizio"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataInizio", + + return df + + +def errOre543DataFine(df): + sheet = "sheet1" + condizione1 = df[sheet]["DataFine"] < pd.to_datetime( + COSTANTI[ANNO_RIFERIMENTO]["datafine543"], format="%d.%m.%Y" + ) + condizione2 = df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander("Trovati errori fine prima di lockdown") + with expndr: + st.info("Tabella con errori fine prima di lockdown") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataFinexxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errOre543DataFine"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataFine", + + return df + + +def errComuneProvenienza(df): + sheet = "sheet1" + condizione1 = df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(df[sheet]["ComuneProvenienza"]) + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento comune provenienza per utente comunale" + ) + with expndr: + st.info( + "Tabella con valori mancanti per comune di proivenienza per utente comunale" + ) + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errComuneProvenienzaxxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errComuneProvenienza"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errComuneProvenienza", + + return df + + +def errCompilazione666(df): + sheet = "sheet1" + condizione1 = df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(df[sheet]["delibera666"]) + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 666 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 666 per utente comunale") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione666xxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errCompilazione666"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione666", + + return df + + +def errCompilazione543(df): + sheet = "sheet1" + condizione1 = df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(df[sheet]["delibera543"]) + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 543 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 543 per utente comunale") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione543xxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errCompilazione543"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione543", + + return df + + +def errCompilazioneEntrate(df): + sheet = "sheet1" + condizione1 = df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(df[sheet]["Entrate"]) + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento entrate per utente comunale") + with expndr: + st.info("Tabella con valori mancanti per entrate per utente comunale") + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazioneEntratexxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errCompilazioneEntrate"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazioneEntrate", + + return df + + +def errDataInizioAnnoRiferimento(df): + sheet = "sheet0" + condizione = df[sheet]["DataInizio"].dt.year >= int(ANNO_RIFERIMENTO) + + if not df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori anno inizio utenti precedenti (foglio 0) maggiore di anno riferimento {ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + f"Tabella con valori erratti per anno inizio utenti precedenti (foglio 1) maggiore di anno riferimento {ANNO_RIFERIMENTO}" + ) + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioAnnoRiferimentoxxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errDataInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errDataInizioAnnoRiferimento", + + return df + + +def errOccorrenzeBambino(df): + sheet = "sheet0" + condizione1 = df[sheet].groupby("Cognome")["DataInizio"].transform("nunique") == 1 + condizione2 = df[sheet].groupby("Cognome")["Ente"].transform("nunique") > 1 + condizione = condizione1 & condizione2 + if not df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + with expndr: + st.info( + "Tabella con errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + make_grid( + df[sheet][condizione].sort_values(by=["Cognome"]), + "errOccorrenzeBambinoxxx", + ) + # settiamo flag bool + df[sheet].loc[condizione, "errOccorrenzeBambino"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errOccorrenzeBambino") + + return df + + +################################# FINE CHECKS + + +def get_data(uploaded_files): + df = {} + dfout = {} + # siccome dobbiamo caricare excel con 2 sheet + dfout["sheet0"] = None + dfout["sheet1"] = None + + STATUS.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + # status = st.empty() + # st.info("") + # st.info("INTEGRITÀ DATI") + with TAB1: + for uploaded_file in uploaded_files: + try: + STATUS2.info("[*] " + uploaded_file.name + " caricato") + df1 = pd.read_excel(uploaded_file, 0,dtype={'Unnamed: 4': dt.datetime}) # sheet 0 + df2 = pd.read_excel(uploaded_file, 1,dtype={'Unnamed: 4': dt.datetime}) # sheet 1 + df["sheet0"] = df1 + df["sheet1"] = df2 + except ValueError as errore_riscontrato: + st.error( + uploaded_file.name + + " non è un file Excel. Errore riscontrato: " + + str(errore_riscontrato) + ) + continue + + # lasciamo prepare_data qui? + try: + STATUS2.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file.name) + except ValueError as errore_riscontrato: + st.error( + f"{str(uploaded_file.name)} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione. Errore: {str(errore_riscontrato)}" + ) + continue + + # se dfout-foglio-0 non esiste lo creiamo + if dfout["sheet0"] is None: + dfout["sheet0"] = pd.DataFrame(columns=df["sheet0"].columns) + dfout["sheet0"] = df["sheet0"].copy() + del df["sheet0"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout["sheet0"] = pd.concat([dfout["sheet0"], df["sheet0"]]) + del df["sheet0"] + # se dfout-foglio-1 non esiste lo creiamo + if dfout["sheet1"] is None: + dfout["sheet1"] = pd.DataFrame(columns=df["sheet1"].columns) + dfout["sheet1"] = df["sheet1"].copy() + del df["sheet1"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout["sheet1"] = pd.concat([dfout["sheet1"], df["sheet1"]]) + del df["sheet1"] + + # ora sono tutti concatenati e possiamo restituire il dataframe + # condizione soddisfatta soltanto se entrambi i sheet non sono vuoti + if not dfout["sheet0"].empty and not dfout["sheet1"].empty: + STATUS2.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + return dfout + + +def prepare_data(df, fn): + # togliamo le colonne inutili e definiamo nomi colonne + df["sheet0"] = df["sheet0"].drop(["Unnamed: 6", "Unnamed: 7"], axis=1) + df["sheet0"].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + + # può capitare che i colleghi scrivano nelle colonne a fianco di quelle che ci interessano + # e quindi eliminiamo le colonne oltre la decima + df["sheet1"] = df["sheet1"].drop(df["sheet1"].iloc[:, 10:], axis=1) + df["sheet1"].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ] + + # aggiungiamo le colonne bool + + df = make_bool_columns(df) + + for a in (0, 1): + # ciclo da foglio 0 a foglio 1 + sheet = "sheet" + str(a) + # estrazione nome microstruttura + microstruttura = df[sheet].iloc[1] + microstruttura = microstruttura[1] + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(microstruttura, str) + if not res: + st.error( + f"Manca informazione MICROSTRUTTURA nel foglio {a+1} nel file --> {fn}" + ) + microstruttura = "assente" + # settiamo flag bool + df[sheet]["dataErrMicrostruttura"] = True + # estrazione nome ente + ente = df[sheet].iloc[2] + ente = ente[1] + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(ente, str) + if not res: + st.error(f"Manca informazione GESTORE nel foglio {a+1} nel file --> {fn}") + ente = "assente" + # settiamo flag bool + df[sheet]["dataErrGestore"] = True + + # inseriamo microstruttura ed ente nel df per foglio elaborato + df[sheet].insert(0, "Microstruttura", microstruttura) + df[sheet].insert(0, "Ente", ente) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df[sheet].insert(0, "filename", fn) + + # togliamo le prime 6 righe perché non servono più + df[sheet] = df[sheet].drop(labels=range(0, 6), axis=0) + + # selezioniamo soltanto record con un valore nel campo cognome + validi = df[sheet]["Cognome"].notna() + df[sheet] = df[sheet][validi] + + # i dati possono contenere valori data invalidi + # siccome trattiamo i dati in un df e definiamo la colonna come *datetime64* + # dobbiamo intercettare le date invalide + conditionInizio = pd.to_datetime( + df[sheet]["DataInizio"], errors="coerce" + ).isnull() + conditionFine = pd.to_datetime(df[sheet]["DataFine"], errors="coerce").isnull() + condition = conditionInizio | conditionFine + + # controlliamo se ci sono date invalide in dataFine e dataInizio + if not df[sheet][condition].empty: + expndr = st.expander( + f"Trovati {len(df[sheet][condition])} errori formato data in foglio {a+1} del file --> {fn}" + ) + with expndr: + st.info("Errori nel formato della data inizio o data fine") + make_grid( + df[sheet][condition].sort_values(by=["Cognome"]), + "errformatodate" + sheet + fn, + ) + # settiamo la colonna bool + df[sheet].loc[condition, "errData"] = True + + # SOLUZIONE TEMPORANEA (?) + # se restituiamo con la data invalida crea problemi in seguito + # quindi visto che abbiamo segnalato l'errore + # creiamo il df pulito + df[sheet] = df[sheet][~condition] + + # infine definiamo le colonne data come data + # tolto il formato perche' e' meglio non forzare il formato + df[sheet]["DataInizio"] = pd.to_datetime( + df[sheet]["DataInizio"] + ) #, format="%d.%m.%Y") + df[sheet]["DataFine"] = pd.to_datetime( + df[sheet]["DataFine"] + ) #, format="%d.%m.%Y") + + # sostituiamo valori nulli nella colonna nome con "manca nome" + df[sheet]['Nome'] = df[sheet]['Nome'].replace(np.nan,'Manca Nome') + + return df + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo dinamicamente le checkbox e i valori in base al + # dictionary che contiene la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + + for chiave_errore in ERRORDICT.items(): + # creiamo i nomi delle variabili in modo dinamico + # *chiave_errore* è la key che rappresenta l'errore in questione + # *a* è il contatore per avere 4 checkboxes per riga + locals()[f"{chiave_errore[0]}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[chiave_errore[0]], value=attivatutti, key=chiave_errore[0] + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict dei controlli il nome del controllo + # e il valore bool della checkbox (selezionato o no) + checks[chiave_errore[0]] = locals()[f"{chiave_errore[0]}"] + + return checks + + +def check_data2(df, checks): + # iteriamo i controlli + with TAB2: + # st.info("") + # st.info("ERRORI NEI DATI") + for tipo_controllo in checks.keys(): + # per ogni controllo vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[tipo_controllo]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome del tipo controllo + funzione = globals()[tipo_controllo] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +def make_grid(dff, k): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +def make_bool_columns(df): + # aggiungiamo le colonne bool per ogni errore/controllo che abbiamo definito in ERRORDICT + # ci serve per creare la tabella finale e per avere uno storico + for a in (0, 1): + sheet = "sheet" + str(a) + for chiave_errore in ERRORDICT.items(): + df[sheet][chiave_errore[0]] = np.nan + df[sheet][chiave_errore[0]] = df[sheet][chiave_errore[0]].astype("boolean") + + return df + + +def drop_columns(df): + # toglie le colonne bool + for chiave_errore in ERRORDICT.items(): + df = df.drop([chiave_errore[0]], axis=1) + return df + + +app() diff --git a/pages/Betriebliche_Kitas_2.py.old b/pages/Betriebliche_Kitas_2.py.old new file mode 100644 index 0000000000000000000000000000000000000000..1a2ab2c56289a713c0ba872f842022f8b5fc6626 --- /dev/null +++ b/pages/Betriebliche_Kitas_2.py.old @@ -0,0 +1,230 @@ +import numpy as np +import pandas as pd + +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + + +class make_interface(): + + def __init__(self): + self.choose_files() + self.choose_checks2() + + st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="🤗" # 👽 + ) + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader( + "Controllo errori BETRIEBLICHE KITAS (v. 2.0.0.0)" + ) + + st.sidebar.markdown(f"# Controlli KITA") + STATUS = st.sidebar.empty() + ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", ("2019", "2020", "2021", "2022") + ) + + DEBUGMODE = st.sidebar.checkbox("Debug mode per controllo sovvraposizione temporale") + + ERRORDICT2019 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2021 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT = {"2019": ERRORDICT2019, "2020": ERRORDICT2020, "2021": ERRORDICT2021} + + costanti_2020 = { + "datainiziomin": "01.01.2017", + "datainiziomax": "31.12.2020", + "datafine": "31.12.2023", + "datainizio543": "23.11.2020", + "datafine543": "24.02.2020", + "datafineassistenza_foglio1": "01.01.2020", + "datafineassistenza_foglio0": "01.01.2020", + } + + costanti_2019 = { + "datainiziomin": "01.01.2016", + "datainiziomax": "31.12.2019", + "datafine": "31.12.2022", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2019", + "datafineassistenza_foglio0": "01.01.2019", + } + + costanti_2021 = { + "datainiziomin": "01.01.2018", + "datainiziomax": "31.12.2021", + "datafine": "31.12.2024", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2021", + "datafineassistenza_foglio0": "01.01.2021", + } + + COSTANTI = {"2020": costanti_2020, "2019": costanti_2019, "2021": costanti_2021} + + def choose_files(self): + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + return uploaded_files + + def choose_checks2(self): + checks = {} + st.write("") + a = 1 + # creiamo dinamicamente le checkbox e i valori in base al + # dictionary che contiene la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + try: + with expndr: + st.write("") + if self.ERRORDICT[self.ANNO_RIFERIMENTO]: + attivatutti = expndr.checkbox("Selezionare/deselezionare tutti i controlli", value=True) + for chiave_errore in self.ERRORDICT[self.ANNO_RIFERIMENTO].items(): + # creiamo i nomi delle variabili in modo dinamico + # *chiave_errore* è la key che rappresenta l'errore in questione + # *a* è il contatore per avere 4 checkboxes per riga + locals()[f"{chiave_errore[0]}"] = locals()[f"c{a}"].checkbox( + self.ERRORDICT[self.ANNO_RIFERIMENTO][chiave_errore[0]], value=attivatutti, key=chiave_errore[0] + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict dei controlli il nome del controllo + # e il valore bool della checkbox (selezionato o no) + checks[chiave_errore[0]] = locals()[f"{chiave_errore[0]}"] + + except Exception as e: + with expndr: + st.warning("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + + return checks + + def make_tabs(): + global TAB1, TAB2, TAB3, TAB4 + TAB1, TAB2, TAB3, TAB4 = st.tabs( + [ + "ERRORI INTEGRITÀ DATI", + "ERRORI NEI DATI", + "ERRORI SOVRAPPOSIZIONE TEMPORALE", + "TABELLE FINALI", + ] + ) + + +if __name__ == "__main__": + #make_tabs() # spostarlo dove viene attivato secondo necessita' + interface = make_interface() + + + + diff --git a/pages/Betriebliche_Kitas_2.py.old2.working b/pages/Betriebliche_Kitas_2.py.old2.working new file mode 100644 index 0000000000000000000000000000000000000000..a50d05962f9c79e8978d6c03a4f2697e33a8a57d --- /dev/null +++ b/pages/Betriebliche_Kitas_2.py.old2.working @@ -0,0 +1,1131 @@ +import numpy as np +import pandas as pd +import datetime as dt +import copy + +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + + +class valoriEtErrori(): + + ERRORDICT2019 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2021 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT = {"2019": ERRORDICT2019, "2020": ERRORDICT2020, "2021": ERRORDICT2021} + + costanti_2020 = { + "datainiziomin": "01.01.2017", + "datainiziomax": "31.12.2020", + "datafine": "31.12.2023", + "datainizio543": "23.11.2020", + "datafine543": "24.02.2020", + "datafineassistenza_foglio1": "01.01.2020", + "datafineassistenza_foglio0": "01.01.2020", + } + + costanti_2019 = { + "datainiziomin": "01.01.2016", + "datainiziomax": "31.12.2019", + "datafine": "31.12.2022", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2019", + "datafineassistenza_foglio0": "01.01.2019", + } + + costanti_2021 = { + "datainiziomin": "01.01.2018", + "datainiziomax": "31.12.2021", + "datafine": "31.12.2024", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2021", + "datafineassistenza_foglio0": "01.01.2021", + } + + COSTANTI = {"2020": costanti_2020, "2019": costanti_2019, "2021": costanti_2021} + + DIZIONARIO = {"2019" : + {"ERRORDICT" : ERRORDICT2019, + "COSTANTI" : costanti_2019, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + } + }, + {"2020" : + {"ERRORDICT" : ERRORDICT2020, + "COSTANTI" : costanti_2020, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + } + }, + {"2021" : + {"ERRORDICT" : ERRORDICT2021, + "COSTANTI" : costanti_2021, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + } + } + + +class make_interface(): + + st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="👽" # 👽 🤗 + ) + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori BETRIEBLICHE KITAS (v. 1.0.0.2)") + st.sidebar.markdown(f"## Impostazioni controlli KITA") + + def __init__(self, ERRORDICT): + self.ERRORDICT = ERRORDICT + self.ANNO_RIFERIMENTO = st.sidebar.selectbox("ANNO RIFERIMENTO", ("2019", "2020", "2021", "2022")) + self.DEBUGMODE = st.sidebar.checkbox("Debug sovrapposizione temporale") + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.make_form() + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.choose_files() + self.choose_checks() + self.make_tabs() + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + self.checks = {} + st.write("") + a = 1 + # creiamo dinamicamente le checkbox e i valori in base al + # dictionary che contiene la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + try: + with expndr: + st.write("") + if self.ERRORDICT[self.ANNO_RIFERIMENTO]: + attivatutti = expndr.checkbox("Selezionare/deselezionare tutti i controlli", value=True) + for chiave_errore in self.ERRORDICT[self.ANNO_RIFERIMENTO].items(): + # creiamo i nomi delle variabili in modo dinamico + # *chiave_errore* è la key che rappresenta l'errore in questione + # *a* è il contatore per avere 4 checkboxes per riga + locals()[f"{chiave_errore[0]}"] = locals()[f"c{a}"].checkbox( + self.ERRORDICT[self.ANNO_RIFERIMENTO][chiave_errore[0]], value=attivatutti, key=chiave_errore[0] + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict dei controlli il nome del controllo + # e il valore bool della checkbox (selezionato o no) + self.checks[chiave_errore[0]] = locals()[f"{chiave_errore[0]}"] + + except Exception as e: + with expndr: + st.warning("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3, self.TAB4 = st.tabs( + [ + "ERRORI INTEGRITÀ DATI", + "ERRORI NEI DATI", + "ERRORI SOVRAPPOSIZIONE TEMPORALE", + "TABELLE FINALI", + ] + ) + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def make_grid(self, df, key): + # togliamo le colonne bool + df = self.drop_columns(df) + gridOptions = self.buildGrid(df) + dfgrid = AgGrid(df, gridOptions=gridOptions, enable_enterprise_modules=True, key=key) + return dfgrid + + def drop_columns(self, df): + # toglie le colonne bool + for chiave_errore in interface.ERRORDICT[interface.ANNO_RIFERIMENTO].items(): + df = df.drop([chiave_errore[0]], axis=1) + return df + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +class trova_errori(): + + dffinal = None + + def __init__(self, valori, interface, df): + self.checks = interface.checks + self.COSTANTI= valori.COSTANTI + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.df = df + self.check_data() + + + def check_data(self): + # iteriamo i controlli + # questo method chiama tutti i method che hanno una entry nel dict dei controlli da fare + with interface.TAB2: + if interface.DEBUGGENERAL: st.info("entered check_data") + # st.info("ERRORI NEI DATI") + #st.write(locals()) + for tipo_controllo in self.checks.keys(): + if tipo_controllo == "errTimeSeries": continue + # per ogni controllo vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if self.checks[tipo_controllo]: + if interface.DEBUGGENERAL: st.write(tipo_controllo) + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome del tipo controllo + try: + eval("self." + tipo_controllo + "()") # non passiamo df perche' usiamo self.df + except Exception as e: + st.error("La funzione " + tipo_controllo + " non e' stata trovata o altro errore: " + str(e) ) + + with interface.TAB3: # tolto dal loop perche' vogliamo l'output sul tab3 e se non e' l'ultima entry nel dict non funzionerebbe + try: + eval("self.errTimeSeries()") + except Exception as e: + st.error("La funzione errTimeSeries non e' stata trovata o altro errore: " + str(e) ) + + with interface.TAB4: + # st.info("") + # st.info("TABELLE FINALI") + expndr = st.expander( + "TABELLA RIASSUNTIVA ELENCO UTENTI PRECEDENTI (FOGLIO 0)" + ) + with expndr: + st.info("Tabella riassuntiva elenco utenti precedenti") + interface.make_grid( + self.df["sheet0"].sort_values(by=["DataInizio"]), "riassunto0" + ) + + expndr = st.expander("TABELLA RIASSUNTIVA ELENCO UTENTI (FOGLIO 1)") + with expndr: + st.info("Tabella riassuntiva elenco utenti") + interface.make_grid( + self.df["sheet1"].sort_values(by=["DataInizio"]), "riassunto1" + ) + + + self.df["sheet0"].to_excel("pippuzzo0.xlsx") + self.df["sheet1"].to_excel("pippuzzo1.xlsx") + + def errPluriNominato(self): + + # qui scegliamo una soluzione diversa dal solito + # lavoriamo con *insiemi* + # creiamo nuovo df con nomi che hanno stessa data inizio su entrambi i fogli + df_same_data_inizio = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataInizio"], how="inner") + + # creiamo nuovo df con nomi che hanno stessa data fine su entrambi i fogli + df_same_data_fine = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataFine"], how="inner") + + # se uno dei due df non è vuoto abbiamo la condizione di errore + if not df_same_data_inizio.empty or not df_same_data_fine.empty: + expndr = st.expander("Trovati bambini con stessa data inizio o stessa data fine o entrambe le date uguali (in riferimento ai due fogli)") + with expndr: + st.info("Tabella con utenti che hanno la stessa data inizio o fine o entrambi (in riferimento ai due fogli)") + # uniamo i due df con un outer join + df_same_data = pd.merge( + df_same_data_inizio, + df_same_data_fine, + on=["Cognome", "Nome"], + how="outer", + ) + + # facciamo la aggrid qui per semplicità anche se non è soluzione elegante + gridOptions = interface.buildGrid(df_same_data) + AgGrid( + df_same_data, + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="same_data_fine_inizio", + ) + + # non definiamo le colonne bool, visto l'approccio usato + + def errTimeSeries(self): + + #with interface.TAB3: + + # st.info("") + st.info("SOVRAPPOSIZIONI TEMPORALI UTENTI COMUNALI E AZIENDALI - CANDIDATI PER ESCLUSIONE") + # questo è il controllo più complesso, still work in progress + + # aggiungiamo la colonna *delibera666* perché dopo ci serve + self.df["sheet0"]["delibera666"] = 0 + + # creiamo una lista con entrambi i df + # possiamo dire quale colonne prendere dal sheet1 con la sintassi che segue + frames = [ + self.df["sheet0"], + self.df["sheet1"][ + [ + "Ente", + "Microstruttura", + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + ] + ], + ] + + # uniamo i due df - ora i contenuti di sheet0 e sheet1 sono in un unico df + result = pd.concat(frames) + result = result.drop("filename", axis=1) + # ordiniamo tutto per data inizio + result = result.sort_values(by=["DataInizio"]) + + # dobbiamo intercettare ed eliminare righe con lo stesso Cognome, Nome, Utenza, DataInizio, DataFine + # bisogna vedere se questa soluzione va bene + + result.drop_duplicates(subset=["Cognome", "Nome", "utente", "DataInizio", "DataFine"], inplace=True) + + # resettiamo l'indice in modo che inizi da 0 + result = result.reset_index() + # potrebbe servire per debug + if interface.DEBUGMODE: + try: + result.to_excel("dataframePrimaDiAlgoritmo.xlsx") + except Exception as e: + st.error("Could not save dataframe to file, reason: " + str(e)) + + # inizializziamo i contatori per utenti comunali e aziendali + cont_a = 0 + cont_c = 0 + + # inizializziamo le liste con le date fine incontrate durante l'iterazione sui record del df + datafineprecedenti_c = [] + datafineprecedenti_a = [] + + st.write("################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + # dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice + for ind in result.index: + # si tratta di utente comunale? + if result["utente"][ind] == "comunale": + cont_c += 1 # incrementiamo il contatore + datafineprecedenti_c.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + d_c = copy.copy(datafineprecedenti_c) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente in (datafineprecedenti_c): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente comunale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore comunale valore attuale = " + + str(cont_c) + ) + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore comunale = " + str(cont_c)) + d_c.remove(datafine_precedente) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_c = copy.copy(d_c) # deep copy della lista aggiornata (senza data fine "consumate") + + # si tratta di utente aziendale? + elif result["utente"][ind] == "aziendale": + cont_a += 1 # incrementiamo il contatore + datafineprecedenti_a.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + d_a = copy.copy(datafineprecedenti_a) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente_aziendale in (datafineprecedenti_a): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente_aziendale): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente aziendale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore aziendale valore attuale = " + + str(cont_a) + ) + cont_a -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore aziendale = " + str(cont_a)) + d_a.remove(datafine_precedente_aziendale) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_a = copy.copy(d_a) # deep copy della lista aggiornata (senza data fine "consumate") + + if interface.DEBUGMODE: + try: + st.write("STATO ATTUALE CONTATORE: bimbo " + result["utente"][ind] + "\t--> " + result["Cognome"][ind] + " " + result["Nome"][ind] + " \t--> contatore comunale = " + str(cont_c) + " e contatore aziendale = " + str(cont_a)) + except: + st.error(f"ATTENZIONE! Trovato errore per il seguente utente: Cognome = {result['Cognome'][ind]} Nome = {result['Nome'][ind]} utente = {result['utente'][ind]}") + #st.error(f"utente = {result['utente'][ind]}") + #st.error(f"Cognome = {result['Cognome'][ind]}") + #st.error(f"Nome = {result['Nome'][ind]}") + # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta + if ( + (cont_c >= cont_a) + and result["utente"][ind] == "comunale" + and result["DataInizio"][ind] + >= pd.to_datetime("03.10.2017", format="%d.%m.%Y") + ): + + # st.write("trovato!!!!!!!") + try: + st.warning(f"[*] Bimba/o {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {str(result['delibera666'][ind])}") + except: + st.error("nel 666") + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write( + "tolto bimbo: contatore comunale = " + + str(cont_c) + + " e contatore aziendale = " + + str(cont_a) + ) + st.write() + st.write("################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + def errElencoUtenti0(self): # controllo data fine assistenza minore di un certo valore, foglio 0 + sheet = "sheet0" + condizione = self.df[sheet]["DataFine"] < pd.to_datetime(self.COSTANTI[self.ANNO_RIFERIMENTO]["datafineassistenza_foglio0"], format="%d.%m.%Y") + + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander(f"Trovati errori ELENCO UTENTI PRECEDENTI per anno di riferimento {self.ANNO_RIFERIMENTO} sul PRIMO FOGLIO") + with expndr: + st.info("Tabella con errori ELENCO UTENTI PRECEDENTI in riferimento ad anno di riferimento sul PRIMO FOGLIO") + interface.make_grid(self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errElencoUtentixxx") + # settiamo flag bool + self.df[sheet].loc[~condizione, "errElencoUtenti0"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + # + + def errTipoKitas(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = self.df[sheet]["utente"] != "comunale" + condizione2 = self.df[sheet]["utente"] != "aziendale" + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander(f"Trovati errori nella descrizione tipo Kitas nel foglio {a+1}") + with expndr: + st.info("Errori riscontrati nella descrizione della tipologia Kitas") + interface.make_grid(self.df[sheet][condizione].sort_values(by=["Cognome"]),"errTipoKitas" + str(a),) + # settiamo flag bool + self.df[sheet].loc[condizione, "errTipoKitas"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori tipologia Kitas", + # "errTipoKitas", + # ) + + def errDataInizioFine(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = self.df[sheet]["DataInizio"] > self.df[sheet]["DataFine"] + if not self.df[sheet][condizione].empty: + expndr = st.expander(f"Trovati errori nel rapporto data fine vs data inizio nel foglio {a+1}") + with expndr: + st.info("Errori riscontrati; data inizio_maggiore data_fine") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioFine" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errDataInizioFine"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errDataInizioFine", + # ) + + def errNome(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = pd.isnull(self.df[sheet]["Nome"]) + condizione2 = pd.isnull(self.df[sheet]["Cognome"]) + condizione = condizione1 | condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati valori nulli per cognome o nome o entrambi nel foglio {a+1}" + ) + with expndr: + st.info("Tabella con cognome o nome o entrambi assenti") + make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errNome" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errNome"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # " + + def errInizioAnnoRiferimento(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = self.df[sheet]["DataInizio"] > pd.to_datetime( + self.COSTANTI[self.ANNO_RIFERIMENTO]["datainiziomin"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["DataInizio"] < pd.to_datetime( + self.COSTANTI[self.ANNO_RIFERIMENTO]["datainiziomax"], format="%d.%m.%Y" + ) + condizione = condizione1 & condizione2 + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data inizio in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO} nel foglio {a+1}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data inizio in riferimento ad anno di riferimento" + ) + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), + "errInizioAnnoRiferimento" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # + + def errFineAnnoRiferimento(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = self.df[sheet]["DataFine"] < pd.to_datetime( + self.COSTANTI[self.ANNO_RIFERIMENTO]["datafine"], format="%d.%m.%Y" + ) + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data fine in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data fine in riferimento ad anno di riferimento" + ) + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), + "errFineAnnoRiferimento" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errFineAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + + + def errOre666(self): + sheet = "sheet1" + condizione = self.df[sheet]["delibera666"] > 0 + if not self.df[sheet][~condizione].empty: + expndr = st.expander(f"Trovati errori per valori in Delibera 666") + with expndr: + st.info("Tabella con errori riscontrati per delibera 666") + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errOre666xxx" + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errOre666"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre666", + + def errOre543DataInizio(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["DataInizio"] > pd.to_datetime( + self.COSTANTI[self.ANNO_RIFERIMENTO]["datainizio543"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento post Notbetreuung") + with expndr: + st.info("Tabella con errori inserimento post Notbetreuung") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataInizioxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOre543DataInizio"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataInizio", + + def errOre543DataFine(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["DataFine"] < pd.to_datetime( + self.COSTANTI[self.ANNO_RIFERIMENTO]["datafine543"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori fine prima di lockdown") + with expndr: + st.info("Tabella con errori fine prima di lockdown") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataFinexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOre543DataFine"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataFine", + + def errComuneProvenienza(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["ComuneProvenienza"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento comune provenienza per utente comunale" + ) + with expndr: + st.info( + "Tabella con valori mancanti per comune di proivenienza per utente comunale" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errComuneProvenienzaxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errComuneProvenienza"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errComuneProvenienza", + + def errCompilazione666(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera666"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 666 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 666 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione666xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione666"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione666", + + def errCompilazione543(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera543"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 543 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 543 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione543xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione543"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione543", + + def errCompilazioneEntrate(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["Entrate"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento entrate per utente comunale") + with expndr: + st.info("Tabella con valori mancanti per entrate per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazioneEntratexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazioneEntrate"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazioneEntrate", + + def errDataInizioAnnoRiferimento(self): + sheet = "sheet0" + condizione = self.df[sheet]["DataInizio"].dt.year >= int(self.ANNO_RIFERIMENTO) + + if not self.df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori anno inizio utenti precedenti (foglio 0) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + f"Tabella con valori erratti per anno inizio utenti precedenti (foglio 1) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioAnnoRiferimentoxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errDataInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errDataInizioAnnoRiferimento", + + def errOccorrenzeBambino(self): + sheet = "sheet0" + condizione1 = self.df[sheet].groupby("Cognome")["DataInizio"].transform("nunique") == 1 + condizione2 = self.df[sheet].groupby("Cognome")["Ente"].transform("nunique") > 1 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + with expndr: + st.info( + "Tabella con errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOccorrenzeBambinoxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOccorrenzeBambino"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errOccorrenzeBambino") + +class caricaEtControlla(): + + + dfout = {} + # siccome dobbiamo caricare excel con 2 sheet + dfout["sheet0"] = None + dfout["sheet1"] = None + + def __init__(self, interface): + self.flag = 0 + self.df = {} # meglio metterlo fuori da __init__ ? + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + interface.STATUS.info("Sono stati caricati " + str(len(self.filelist)) + " files") + self.carica_dati() + + def carica_dati(self): + + with interface.TAB1: + if interface.DEBUGGENERAL: st.write("entrato carica_dati") + for file in self.filelist: + try: # carica tutti i file dell lista + interface.STATUS2.info(file.name + " caricato") + df1 = pd.read_excel(file, 0) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 0 + df2 = pd.read_excel(file, 1) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 1 + self.df["sheet0"] = df1 + self.df["sheet1"] = df2 + except ValueError as errore_riscontrato: + st.error( + file.name + + " non è un file Excel. Errore riscontrato: " + + str(errore_riscontrato) + ) + continue # se errore passiamo al prossimo file + #st.write(df1) + #st.write(df2) + try: # inizia la preparazione dei dati + interface.STATUS2.info(f"{file.name} elaborato") + self.df = self.prepare_data(self.df, file.name) + except ValueError as errore_riscontrato: + st.error( + f"{str(file.name)} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione. Errore: {str(errore_riscontrato)}" + ) + continue # se errore passiamo al prossimo file + + # se dfout-foglio-0 non esiste lo creiamo + if self.dfout["sheet0"] is None: + self.dfout["sheet0"] = pd.DataFrame(columns=self.df["sheet0"].columns) + self.dfout["sheet0"] = self.df["sheet0"].copy() + del self.df["sheet0"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet0"] = pd.concat([self.dfout["sheet0"], self.df["sheet0"]]) + del self.df["sheet0"] + # se dfout-foglio-1 non esiste lo creiamo + if self.dfout["sheet1"] is None: + self.dfout["sheet1"] = pd.DataFrame(columns=self.df["sheet1"].columns) + self.dfout["sheet1"] = self.df["sheet1"].copy() + del self.df["sheet1"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet1"] = pd.concat([self.dfout["sheet1"], self.df["sheet1"]]) + del self.df["sheet1"] + #st.write(self.dfout["sheet1"]) + # ora sono tutti concatenati e possiamo restituire il dataframe + # condizione soddisfatta soltanto se entrambi i sheet non sono vuoti + if not self.dfout["sheet0"].empty and not self.dfout["sheet1"].empty: + interface.STATUS2.success( + "Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + if interface.DEBUGGENERAL: st.write(self.dfout["sheet0"]), st.write(self.dfout["sheet1"]) + + + def prepare_data(self, df, file_name): + if interface.DEBUGGENERAL: st.write("elaboro " + file_name) + # togliamo le colonne inutili e definiamo nomi colonne + df["sheet0"] = df["sheet0"].drop(["Unnamed: 6", "Unnamed: 7"], axis=1) + df["sheet0"].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + + # può capitare che i colleghi scrivano nelle colonne a fianco di quelle che ci interessano + # e quindi eliminiamo le colonne oltre la decima (per anni 2019, 2020) + # e oltre la nona per anno 2021 + if self.ANNO_RIFERIMENTO in ['2019', '2020']: + df["sheet1"] = df["sheet1"].drop(df["sheet1"].iloc[:, 10:], axis=1) + df["sheet1"].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ] + elif self.ANNO_RIFERIMENTO == '2021': + df["sheet1"] = df["sheet1"].drop(df["sheet1"].iloc[:, 9:], axis=1) + df["sheet1"].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + #"delibera543", + "delibera733", + "Entrate", + ] + df = self.make_bool_columns(df) + + for a in (0, 1): + # ciclo da foglio 0 a foglio 1 + sheet = "sheet" + str(a) + # estrazione nome microstruttura + microstruttura = df[sheet].iloc[1] + microstruttura = microstruttura[1] + if interface.DEBUGGENERAL: st.write("microstruttura = "+ str(microstruttura)) + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(microstruttura, str) + + if not res: + st.error( + f"Manca informazione MICROSTRUTTURA nel foglio {a+1} nel file --> {file_name}" + ) + microstruttura = "assente" + # settiamo flag bool + df[sheet]["dataErrMicrostruttura"] = True + + # estrazione nome ente + ente = df[sheet].iloc[2] + ente = ente[1] + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(ente, str) + if not res: + st.error(f"Manca informazione GESTORE nel foglio {a+1} nel file --> {file_name}") + ente = "assente" + # settiamo flag bool + df[sheet]["dataErrGestore"] = True + + # inseriamo microstruttura ed ente nel df per foglio elaborato + df[sheet].insert(0, "Microstruttura", microstruttura) + df[sheet].insert(0, "Ente", ente) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df[sheet].insert(0, "filename", file_name) + + # togliamo le prime 6 righe perché non servono più + df[sheet] = df[sheet].drop(labels=range(0, 6), axis=0) + + # selezioniamo soltanto record con un valore nel campo cognome + validi = df[sheet]["Cognome"].notna() + df[sheet] = df[sheet][validi] + + # i dati possono contenere valori data invalidi + # siccome trattiamo i dati in un df e definiamo la colonna come *datetime64* + # dobbiamo intercettare le date invalide + conditionInizio = pd.to_datetime(df[sheet]["DataInizio"], errors="coerce", dayfirst=True).isnull() + conditionFine = pd.to_datetime(df[sheet]["DataFine"], errors="coerce", dayfirst=True).isnull() + condition = conditionInizio | conditionFine + + # controlliamo se ci sono date invalide in dataFine e dataInizio + if not df[sheet][condition].empty: + expndr = st.expander(f"Trovati {len(df[sheet][condition])} errori formato data in foglio {a+1} del file --> {file_name}") + with expndr: + st.info("Errori nel formato della data inizio o data fine") + interface.make_grid( + df[sheet][condition].sort_values(by=["Cognome"]), + "errformatodate" + sheet + file_name, + ) + # settiamo la colonna bool + df[sheet].loc[condition, "errData"] = True + + # se restituiamo con la data invalida crea problemi in seguito + # quindi visto che abbiamo segnalato l'errore + # creiamo il df pulito + df[sheet] = df[sheet][~condition] + + # infine definiamo le colonne data come data + # tolto il formato perche' e' meglio non forzare il formato + + df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + df[sheet]["DataFine"] = pd.to_datetime(df[sheet]["DataFine"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + #df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], format="%d.%m.%Y") + # sostituiamo valori nulli nella colonna nome con "manca nome" + df[sheet]['Nome'] = df[sheet]['Nome'].replace(np.nan,'Manca Nome') + + + + return df + + + def make_bool_columns(self, df): + # aggiungiamo le colonne bool per ogni errore/controllo che abbiamo definito in ERRORDICT + # ci serve per creare la tabella finale e per avere uno storico + for a in (0, 1): + sheet = "sheet" + str(a) + for chiave_errore in interface.ERRORDICT[interface.ANNO_RIFERIMENTO].items(): + if interface.DEBUGGENERAL: st.write(chiave_errore) + df[sheet][chiave_errore[0]] = np.nan + df[sheet][chiave_errore[0]] = df[sheet][chiave_errore[0]].astype("boolean") + + return df + + def get_dfout(self): + dfout = self.dfout + return dfout + +if __name__ == "__main__": + flag = 0 + valori = valoriEtErrori() + interface = make_interface(valori.ERRORDICT) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + + caricaEtControlla(interface) + dfcompleto = caricaEtControlla.dfout + if interface.DEBUGGENERAL: st.write(dfcompleto) + + errori = trova_errori(valori, interface, dfcompleto) + + #interface.make_tabs() + + + diff --git a/pages/Betriebliche_Kitas_2.py.working b/pages/Betriebliche_Kitas_2.py.working new file mode 100644 index 0000000000000000000000000000000000000000..a2c19a866efd7da560071c568e485ecf304461e4 --- /dev/null +++ b/pages/Betriebliche_Kitas_2.py.working @@ -0,0 +1,1255 @@ +import numpy as np +import pandas as pd +import datetime as dt +import copy +import this +import collections + +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + + +class valoriEtErrori(): + + ERRORDICT2019 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + "errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errOre543DataInizio": "Ore 543 su data inizio", + "errOre543DataFine": "Ore 543 su data fine", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + + ERRORDICT2021 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio minore data fine", + "errInizioAnnoRiferimento": "Data inizio per anno riferimento", + "errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT2022 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + "errElencoUtenti0": "Errore elenco utenti PRIMO foglio", + # "errElencoUtenti1": "Errore elenco utenti SECONDO foglio", + "errNome": "Compilazione cognome e nome bambino", + # "dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Tipologia Kitas", + "errDataInizioFine": "Data inizio maggiore data fine", + #"errInizioAnnoRiferimento": "Data inizio per anno riferimento", + #"errFineAnnoRiferimento": "Data fine per anno riferimento", + "errOccorrenzeBambino": "Occorrenze bambino in diverse strutture per stessa data inizio", + "errComuneProvenienza": "Comune provenienza per utente comunale", + "errCompilazione666": "Compilazione ore 666 per utente comunale", + #"errCompilazione543": "Compilazione ore 543 per utente comunale", + "errCompilazioneEntrate": "Compilazione entrate per utente comunale", + "errOre666": "Ore 666 maggiore di zero", + "errDataInizioAnnoRiferimento": "Data inizio foglio 0 minore anno riferimento", + "errPluriNominato": "Kind Mehrfachnennung", + "errTimeSeries": "Sovrapposizioni temporali utenti aziendali e comunali", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", + } + + ERRORDICT = {"2019": ERRORDICT2019, "2020": ERRORDICT2020, "2021": ERRORDICT2021, "2022": ERRORDICT2022} + + costanti_2020 = { + "datainiziomin": "01.01.2017", + "datainiziomax": "31.12.2020", + "datafine": "31.12.2023", + "datainizio543": "23.11.2020", + "datafine543": "24.02.2020", + "datafineassistenza_foglio1": "01.01.2020", + "datafineassistenza_foglio0": "01.01.2020", + } + + costanti_2019 = { + "datainiziomin": "01.01.2016", + "datainiziomax": "31.12.2019", + "datafine": "31.12.2022", + "datainizio543": "23.11.2019", + "datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2019", + "datafineassistenza_foglio0": "01.01.2019", + } + + costanti_2021 = { + "datainiziomin": "01.01.2018", + "datainiziomax": "31.12.2021", + "datafine": "31.12.2024", + #"datainizio543": "23.11.2019", + #"datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2021", + "datafineassistenza_foglio0": "01.01.2021", + } + + costanti_2022 = { + #"datainiziomin": "01.01.2018", + #"datainiziomax": "31.12.2021", + #"datafine": "31.12.2024", + #"datainizio543": "23.11.2019", + #"datafine543": "24.02.2019", + "datafineassistenza_foglio1": "01.01.2022", + "datafineassistenza_foglio0": "01.01.2022", + } + + COSTANTI = {"2020": costanti_2020, "2019": costanti_2019, "2021": costanti_2021, "2022": costanti_2022} + + DIZIONARIO = {"2019" : + {"ERRORDICT" : ERRORDICT2019, + "COSTANTI" : costanti_2019, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 10, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 9 # i valori che si servono per estrarre l'anno in questione dal file Excel + }, + "2020" : + {"ERRORDICT" : ERRORDICT2020, + "COSTANTI" : costanti_2020, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 10, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 9 # i valori che si servono per estrarre l'anno in questione dal file Excel + }, + "2021" : + {"ERRORDICT" : ERRORDICT2021, + "COSTANTI" : costanti_2021, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 9, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 8 # i valori che si servono per estrarre l'anno in questione dal file Excel + }, + "2022" : + {"ERRORDICT" : ERRORDICT2022, + "COSTANTI" : costanti_2022, + "colonne1" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera733", + "Entrate", + ], + "colonne0" : [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ], + "dropAfterColumn" : 9, + "indirizzoAnno_1" : 1, # i valori che si servono per estrarre l'anno in questione dal file Excel + "indirizzoAnno_2" : 8 # i valori che si servono per estrarre l'anno in questione dal file Excel + } + } + + + +class make_interface(): + + st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="👽" # 👽 🤗 + ) + + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori BETRIEBLICHE KITAS (v. 1.0.3production)") + st.sidebar.markdown(f"### Impostazioni controlli BETRIEBLICHE KITAS") + + def __init__(self, DIZIONARIO): + #self.ERRORDICT = ERRORDICT + #currentDateTime = dt.datetime.now() + #date = currentDateTime.date() + #year = date.strftime("%Y") + + self.ANNO_RIFERIMENTO = st.sidebar.selectbox("ANNO RIFERIMENTO", ("2019", "2020", "2021", "2022"), index=2) + self.DEBUGMODE = st.sidebar.checkbox("Debug sovrapposizione temporale") + self.DEBUGWARNINGS = st.sidebar.checkbox("Interrompere con warnings") + self.TOLLERANZAZERO = st.sidebar.checkbox("Tolleranza zero") + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox("Mostra costanti per anno riferimento") + if self.MOSTRACOSTANTI: + #or k in DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"]: + # st.sidebar.info(k + " " + DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"][k]) + st.sidebar.info(DIZIONARIO[self.ANNO_RIFERIMENTO]["COSTANTI"]) + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + try: + self.ERRORDICT = DIZIONARIO[self.ANNO_RIFERIMENTO]["ERRORDICT"] + except Exception as e: + self.STATUS.error("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + if self.TOLLERANZAZERO: st.stop() + + self.make_form() + self.choose_files() + self.choose_checks() + #self.make_tabs() + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + self.checks = {} + st.write("") + a = 1 + # creiamo dinamicamente le checkbox e i valori in base al + # dictionary che contiene la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + try: + with expndr: + st.write("") + if self.ERRORDICT: + attivatutti = expndr.checkbox("Selezionare/deselezionare tutti i controlli", value=True) + for chiave_errore in self.ERRORDICT.items(): + # creiamo i nomi delle variabili in modo dinamico + # *chiave_errore* è la key che rappresenta l'errore in questione + # *a* è il contatore per avere 4 checkboxes per riga + locals()[f"{chiave_errore[0]}"] = locals()[f"c{a}"].checkbox( + self.ERRORDICT[chiave_errore[0]], value=attivatutti, key=chiave_errore[0] + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict dei controlli il nome del controllo + # e il valore bool della checkbox (selezionato o no) + self.checks[chiave_errore[0]] = locals()[f"{chiave_errore[0]}"] + + except Exception as e: + with expndr: + st.warning("Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno " + self.ANNO_RIFERIMENTO + "?") + if self.TOLLERANZAZERO: st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3, self.TAB4 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI NEI DATI", + "SOVRAPPOSIZIONI TEMPORALI", + "TABELLE FINALI", + ] + ) + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def make_grid(self, df, key): + # togliamo le colonne bool + df = self.drop_columns(df) + gridOptions = self.buildGrid(df) + AgGrid(df, gridOptions=gridOptions, enable_enterprise_modules=True, key=key) + #return dfgrid + + def drop_columns(self, df): + # toglie le colonne bool + for chiave_errore in self.ERRORDICT.items(): + df = df.drop([chiave_errore[0]], axis=1) + return df + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + #gb.configure_selection(selection_mode="multiple", use_checkbox=True) + #gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + #) + gridOptions = gb.build() + return gridOptions + + +class trova_errori(): + + dffinal = None + + def __init__(self, dizionario, interface, df): + self.checks = interface.checks + + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.COSTANTI = dizionario[self.ANNO_RIFERIMENTO]["COSTANTI"] + self.df = df + self.check_data() + + + def check_data(self): + # iteriamo i controlli + # questo method chiama tutti i method che hanno una entry nel dict dei controlli da fare + with interface.TAB2: + if interface.DEBUGGENERAL: st.info("entered check_data") + # st.info("ERRORI NEI DATI") + #st.write(locals()) + for tipo_controllo in self.checks.keys(): + if tipo_controllo == "errTimeSeries": continue + # per ogni controllo vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if self.checks[tipo_controllo]: + if interface.DEBUGGENERAL: st.write(tipo_controllo) + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome del tipo controllo + try: + eval("self." + tipo_controllo + "()") # non passiamo df perche' usiamo self.df + except Exception as e: + st.error("La funzione " + tipo_controllo + " non e' stata trovata o altro errore: " + str(e) ) + if interface.TOLLERANZAZERO: st.stop() + + with interface.TAB3: # tolto dal loop perche' vogliamo l'output sul tab3 e se non e' l'ultima entry nel dict non funzionerebbe + try: + eval("self.errTimeSeries()") + except Exception as e: + st.error("La funzione errTimeSeries non e' stata trovata o altro errore: " + str(e) ) + if interface.TOLLERANZAZERO: st.stop() + + with interface.TAB4: + # st.info("") + # st.info("TABELLE FINALI") + expndr = st.expander( + "TABELLA RIASSUNTIVA ELENCO UTENTI PRECEDENTI (FOGLIO 0)" + ) + with expndr: + st.info("Tabella riassuntiva elenco utenti precedenti") + interface.make_grid( + self.df["sheet0"].sort_values(by=["DataInizio"]), "riassunto0" + ) + + expndr = st.expander("TABELLA RIASSUNTIVA ELENCO UTENTI (FOGLIO 1)") + with expndr: + st.info("Tabella riassuntiva elenco utenti") + interface.make_grid( + self.df["sheet1"].sort_values(by=["DataInizio"]), "riassunto1" + ) + + + self.df["sheet0"].to_excel("pippuzzo0.xlsx") + self.df["sheet1"].to_excel("pippuzzo1.xlsx") + + def errPluriNominato(self): + + # qui scegliamo una soluzione diversa dal solito + # lavoriamo con *insiemi* + # creiamo nuovo df con nomi che hanno stessa data inizio su entrambi i fogli + df_same_data_inizio = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataInizio"], how="inner") + + # creiamo nuovo df con nomi che hanno stessa data fine su entrambi i fogli + df_same_data_fine = pd.merge(self.df["sheet0"], self.df["sheet1"], on=["Cognome", "Nome", "DataFine"], how="inner") + + # se uno dei due df non è vuoto abbiamo la condizione di errore + if not df_same_data_inizio.empty or not df_same_data_fine.empty: + expndr = st.expander("Trovati bambini con stessa data inizio o stessa data fine o entrambe le date uguali (in riferimento ai due fogli)") + with expndr: + st.info("Tabella con utenti che hanno la stessa data inizio o fine o entrambi (in riferimento ai due fogli)") + # uniamo i due df con un outer join + df_same_data = pd.merge( + df_same_data_inizio, + df_same_data_fine, + on=["Cognome", "Nome"], + how="outer", + ) + + # facciamo la aggrid qui per semplicità anche se non è soluzione elegante + gridOptions = interface.buildGrid(df_same_data) + AgGrid( + df_same_data, + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="same_data_fine_inizio", + ) + + # non definiamo le colonne bool, visto l'approccio usato + + def errTimeSeries(self): + + #with interface.TAB3: + + # st.info("") + st.info("SOVRAPPOSIZIONI TEMPORALI UTENTI COMUNALI E AZIENDALI - CANDIDATI PER ESCLUSIONE") + # questo è il controllo più complesso, still work in progress + + # aggiungiamo la colonna *delibera666* perché dopo ci serve + self.df["sheet0"]["delibera666"] = 0 + + # creiamo una lista con entrambi i df + # possiamo dire quale colonne prendere dal sheet1 con la sintassi che segue + frames = [ + self.df["sheet0"], + self.df["sheet1"][ + [ + "Ente", + "Microstruttura", + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + ] + ], + ] + + # uniamo i due df - ora i contenuti di sheet0 e sheet1 sono in un unico df + result = pd.concat(frames) + result = result.drop("filename", axis=1) + # ordiniamo tutto per data inizio + result = result.sort_values(by=["DataInizio"]) + + # dobbiamo intercettare ed eliminare righe con lo stesso Cognome, Nome, Utenza, DataInizio, DataFine + # bisogna vedere se questa soluzione va bene + + result.drop_duplicates(subset=["Cognome", "Nome", "utente", "DataInizio", "DataFine"], inplace=True) + + # resettiamo l'indice in modo che inizi da 0 + result = result.reset_index() + # potrebbe servire per debug + if interface.DEBUGMODE: + try: + result.to_excel("dataframePrimaDiAlgoritmo.xlsx") + except Exception as e: + st.error("Could not save dataframe to file, reason: " + str(e)) + if interface.TOLLERANZAZERO: st.stop() + + # inizializziamo i contatori per utenti comunali e aziendali + cont_a = 0 + cont_c = 0 + + # inizializziamo le liste con le date fine incontrate durante l'iterazione sui record del df + datafineprecedenti_c = [] + datafineprecedenti_a = [] + + datafine_c = collections.namedtuple('Data',('datafine','nome')) + datafine_a = collections.namedtuple('Data',('datafine','nome')) + + st.write("################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + # dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice + for ind in result.index: + # si tratta di utente comunale? + try: + if result["utente"][ind].lower() == "comunale": + cont_c += 1 # incrementiamo il contatore + # datafineprecedenti_c.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + datafine = datafine_c(str(result["DataFine"][ind]), str(result["Cognome"][ind]) + " " + str(result["Nome"][ind])) + datafineprecedenti_c.append(datafine) + + d_c = copy.copy(datafineprecedenti_c) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente in (datafineprecedenti_c): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente.datafine): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente comunale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore comunale valore attuale = " + + str(cont_c) + ) + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore comunale = " + str(cont_c) + ", utente relativo alla data trovata: " + datafine_precedente.nome) + d_c.remove(datafine_precedente) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_c = copy.copy(d_c) # deep copy della lista aggiornata (senza data fine "consumate") + + # si tratta di utente aziendale? + elif result["utente"][ind].lower() == "aziendale": + cont_a += 1 # incrementiamo il contatore + # datafineprecedenti_a.append(str(result["DataFine"][ind])) # salviamo la data fine incontrata dureante iterazione + datafine = datafine_a(str(result["DataFine"][ind]), str(result["Cognome"][ind]) + " " + str(result["Nome"][ind])) + datafineprecedenti_a.append(datafine) + + d_a = copy.copy(datafineprecedenti_a) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop + for datafine_precedente_aziendale in (datafineprecedenti_a): # loopiamo tutte le data fine incontrate precedentemente + if (str(result["DataInizio"][ind]) > datafine_precedente_aziendale.datafine): # se incontrata una data inizio superiore a una data fine già incontrata + if interface.DEBUGMODE: + st.write("Trovata data inizio superiore a una data fine gia' incontrata, per utente aziendale " + + result["Cognome"][ind] + + " " + + result["Nome"][ind] + + ", contatore aziendale valore attuale = " + + str(cont_a) + ) + cont_a -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write("Sottrazione --> contatore aziendale = " + str(cont_a) + ", utente relativo alla data trovata: " + datafine_precedente_aziendale.nome) + d_a.remove(datafine_precedente_aziendale) # togliamo la data "consumata" dalla lista (copiata) + datafineprecedenti_a = copy.copy(d_a) # deep copy della lista aggiornata (senza data fine "consumate") + + except Exception as e: + st.error(f'Errore {e} per {result["Nome"][ind]} {result["Cognome"][ind]}, utente: {result["utente"][ind]}') + if interface.TOLLERANZAZERO: st.stop() + continue + + if interface.DEBUGMODE: + try: + st.write("STATO ATTUALE CONTATORE: bimbo " + result["utente"][ind].lower() + "\t--> " + result["Cognome"][ind] + " " + result["Nome"][ind] + " \t--> contatore comunale = " + str(cont_c) + " e contatore aziendale = " + str(cont_a)) + except: + st.error(f"ATTENZIONE! Trovato errore per il seguente utente: Cognome = {result['Cognome'][ind]} Nome = {result['Nome'][ind]} utente = {result['utente'][ind]}") + #st.error(f"utente = {result['utente'][ind]}") + #st.error(f"Cognome = {result['Cognome'][ind]}") + #st.error(f"Nome = {result['Nome'][ind]}") + # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta + if ( + (cont_c >= cont_a) + and result["utente"][ind] == "comunale" + and result["DataInizio"][ind] + >= pd.to_datetime("01.01.2018", format="%d.%m.%Y") + ): + + # st.write("trovato!!!!!!!") + try: + st.warning(f"[*] Bimba/o {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {str(result['delibera666'][ind])}") + except: + st.error("nel 666") + cont_c -= 1 # sottraiamo contatore + if interface.DEBUGMODE: + st.write( + "tolto bimbo: contatore comunale = " + + str(cont_c) + + " e contatore aziendale = " + + str(cont_a) + ) + st.write() + st.write("################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################") + + def errElencoUtenti0(self): # controllo data fine assistenza minore di un certo valore, foglio 0 + sheet = "sheet0" + condizione = self.df[sheet]["DataFine"] < pd.to_datetime(self.COSTANTI["datafineassistenza_foglio0"], format="%d.%m.%Y") + + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander(f"Trovati errori ELENCO UTENTI PRECEDENTI per anno di riferimento {self.ANNO_RIFERIMENTO} sul PRIMO FOGLIO") + with expndr: + st.info("Tabella con errori ELENCO UTENTI PRECEDENTI in riferimento ad anno di riferimento sul PRIMO FOGLIO") + interface.make_grid(self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errElencoUtentixxx") + # settiamo flag bool + self.df[sheet].loc[~condizione, "errElencoUtenti0"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + # + + def errTipoKitas(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = self.df[sheet]["utente"] != "comunale" + condizione2 = self.df[sheet]["utente"] != "aziendale" + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander(f"Trovati errori nella descrizione tipo Kitas nel foglio {a+1}") + with expndr: + st.info("Errori riscontrati nella descrizione della tipologia Kitas") + interface.make_grid(self.df[sheet][condizione].sort_values(by=["Cognome"]),"errTipoKitas" + str(a),) + # settiamo flag bool + self.df[sheet].loc[condizione, "errTipoKitas"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori tipologia Kitas", + # "errTipoKitas", + # ) + + def errDataInizioFine(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = self.df[sheet]["DataInizio"] > self.df[sheet]["DataFine"] + if not self.df[sheet][condizione].empty: + expndr = st.expander(f"Trovati errori nel rapporto data fine vs data inizio nel foglio {a+1}") + with expndr: + st.info("Errori riscontrati; data inizio_maggiore data_fine") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioFine" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errDataInizioFine"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errDataInizioFine", + # ) + + def errNome(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = pd.isnull(self.df[sheet]["Nome"]) + condizione2 = pd.isnull(self.df[sheet]["Cognome"]) + condizione = condizione1 | condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati valori nulli per cognome o nome o entrambi nel foglio {a+1}" + ) + with expndr: + st.info("Tabella con cognome o nome o entrambi assenti") + make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errNome" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errNome"] = True + # x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # " + + def errInizioAnnoRiferimento(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione1 = self.df[sheet]["DataInizio"] > pd.to_datetime( + self.COSTANTI["datainiziomin"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["DataInizio"] < pd.to_datetime( + self.COSTANTI["datainiziomax"], format="%d.%m.%Y" + ) + condizione = condizione1 & condizione2 + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data inizio in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO} nel foglio {a+1}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data inizio in riferimento ad anno di riferimento" + ) + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), + "errInizioAnnoRiferimento" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # + + def errFineAnnoRiferimento(self): + for a in (0, 1): + sheet = "sheet" + str(a) + condizione = self.df[sheet]["DataFine"] < pd.to_datetime( + self.COSTANTI["datafine"], format="%d.%m.%Y" + ) + # invertiamo la condizione + if not self.df[sheet][~condizione].empty: + expndr = st.expander( + f"Trovati errori per data fine in riferimento ad anno di riferimento {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Tabella con errori riscontrati per data fine in riferimento ad anno di riferimento" + ) + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), + "errFineAnnoRiferimento" + str(a), + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errFineAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errInizioAnnoRiferimento", + + + def errOre666(self): + sheet = "sheet1" + condizione = self.df[sheet]["delibera666"] > 0 + if not self.df[sheet][~condizione].empty: + expndr = st.expander(f"Trovati errori per valori in Delibera 666") + with expndr: + st.info("Tabella con errori riscontrati per delibera 666") + interface.make_grid( + self.df[sheet][~condizione].sort_values(by=["Cognome"]), "errOre666xxx" + ) + # settiamo flag bool + self.df[sheet].loc[~condizione, "errOre666"] = True + # x = dwnld( + # df[sheet][~condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre666", + + def errOre543DataInizio(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["DataInizio"] > pd.to_datetime( + self.COSTANTI["datainizio543"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento post Notbetreuung") + with expndr: + st.info("Tabella con errori inserimento post Notbetreuung") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataInizioxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOre543DataInizio"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataInizio", + + def errOre543DataFine(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["DataFine"] < pd.to_datetime( + self.COSTANTI["datafine543"], format="%d.%m.%Y" + ) + condizione2 = self.df[sheet]["delibera543"] > 0 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori fine prima di lockdown") + with expndr: + st.info("Tabella con errori fine prima di lockdown") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOre543DataFinexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOre543DataFine"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errOre543DataFine", + + def errComuneProvenienza(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["ComuneProvenienza"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento comune provenienza per utente comunale" + ) + with expndr: + st.info( + "Tabella con valori mancanti per comune di proivenienza per utente comunale" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errComuneProvenienzaxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errComuneProvenienza"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errComuneProvenienza", + + def errCompilazione666(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera666"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 666 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 666 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione666xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione666"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione666", + + def errCompilazione543(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["delibera543"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori inserimento delibera 543 per utente comunale" + ) + with expndr: + st.info("Tabella con valori mancanti per delibera 543 per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazione543xxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazione543"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazione543", + + def errCompilazioneEntrate(self): + sheet = "sheet1" + condizione1 = self.df[sheet]["utente"] == "comunale" + condizione2 = pd.isnull(self.df[sheet]["Entrate"]) + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander("Trovati errori inserimento entrate per utente comunale") + with expndr: + st.info("Tabella con valori mancanti per entrate per utente comunale") + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errCompilazioneEntratexxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errCompilazioneEntrate"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errCompilazioneEntrate", + + def errDataInizioAnnoRiferimento(self): + sheet = "sheet0" + condizione = self.df[sheet]["DataInizio"].dt.year >= int(self.ANNO_RIFERIMENTO) + + if not self.df[sheet][condizione].empty: + expndr = st.expander( + f"Trovati errori anno inizio utenti precedenti (foglio 0) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + f"Tabella con valori erratti per anno inizio utenti precedenti (foglio 1) maggiore di anno riferimento {self.ANNO_RIFERIMENTO}" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errDataInizioAnnoRiferimentoxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errDataInizioAnnoRiferimento"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errDataInizioAnnoRiferimento", + + def errOccorrenzeBambino(self): + sheet = "sheet0" + condizione1 = self.df[sheet].groupby("Cognome")["DataInizio"].transform("nunique") == 1 + condizione2 = self.df[sheet].groupby("Cognome")["Ente"].transform("nunique") > 1 + condizione = condizione1 & condizione2 + if not self.df[sheet][condizione].empty: + expndr = st.expander( + "Trovati errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + with expndr: + st.info( + "Tabella con errori occorrenze bambino in diverse strutture per stessa data inizio" + ) + interface.make_grid( + self.df[sheet][condizione].sort_values(by=["Cognome"]), + "errOccorrenzeBambinoxxx", + ) + # settiamo flag bool + self.df[sheet].loc[condizione, "errOccorrenzeBambino"] = True + # x = dwnld( + # df[sheet][condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine",iloc + + # "errOccorrenzeBambino") + +class caricaEtControlla(): + + + dfout = {} + # siccome dobbiamo caricare excel con 2 sheet + dfout["sheet0"] = None + dfout["sheet1"] = None + + def __init__(self, interface, dizionario): + self.flag = 0 + self.df = {} # meglio metterlo fuori da __init__ ? + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.DIZIONARIO = valori.DIZIONARIO + interface.STATUS.info("Sono stati caricati " + str(len(self.filelist)) + " files") + self.carica_dati() + + def carica_dati(self): + + with interface.TAB1: + if interface.DEBUGGENERAL: st.write("entrato carica_dati") + for file in self.filelist: + try: # carica tutti i file della lista + interface.STATUS2.info(file.name + " caricato") + df1 = pd.read_excel(file, 0) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 0 + df2 = pd.read_excel(file, 1) #,dtype={'Unnamed: 4': dt.datetime}) # sheet 1 + self.df["sheet0"] = df1 + self.df["sheet1"] = df2 + except ValueError as errore_riscontrato: + st.error( + file.name + + " non è un file Excel. Errore riscontrato: " + + str(errore_riscontrato) + ) + if interface.TOLLERANZAZERO: st.stop() + continue # se errore passiamo al prossimo file + #st.write(df1) + #st.write(df2) + try: # inizia la preparazione dei dati + interface.STATUS2.info(f"{file.name} elaborato") + self.df = self.prepare_data(self.df, file.name) + except ValueError as errore_riscontrato: + st.error(f"{str(file.name)} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione. Errore: {str(errore_riscontrato)}") + #st.warning(f"Probabilmente e' stato scelto un anno riferimento sbagliato ({self.ANNO_RIFERIMENTO}) mentre il file contiene l'anno {anno_estratto}, quindi il file caricato non e' strutturato come previsto per l'anno scelto") + if interface.TOLLERANZAZERO: st.stop() + continue # se errore passiamo al prossimo file + try: + # se dfout-foglio-0 non esiste lo creiamo + if self.dfout["sheet0"] is None: + self.dfout["sheet0"] = pd.DataFrame(columns=self.df["sheet0"].columns) + self.dfout["sheet0"] = self.df["sheet0"].copy() + del self.df["sheet0"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet0"] = pd.concat([self.dfout["sheet0"], self.df["sheet0"]]) + del self.df["sheet0"] + # se dfout-foglio-1 non esiste lo creiamo + if self.dfout["sheet1"] is None: + self.dfout["sheet1"] = pd.DataFrame(columns=self.df["sheet1"].columns) + self.dfout["sheet1"] = self.df["sheet1"].copy() + del self.df["sheet1"] + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + self.dfout["sheet1"] = pd.concat([self.dfout["sheet1"], self.df["sheet1"]]) + del self.df["sheet1"] + except Exception as e: + st.error(f"Errore riscontrato durante il caricamento: {e}") + if interface.TOLLERANZAZERO: st.stop() + continue + #st.write(self.dfout["sheet1"]) + # ora sono tutti concatenati e possiamo restituire il dataframe + # condizione soddisfatta soltanto se entrambi i sheet non sono vuoti + if not self.dfout["sheet0"].empty and not self.dfout["sheet1"].empty: + interface.STATUS2.success( + "Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + if interface.DEBUGGENERAL: st.write(self.dfout["sheet0"]), st.write(self.dfout["sheet1"]) + + + + def prepare_data(self, df, file_name): + if interface.DEBUGGENERAL: st.write("elaboro " + file_name) + # togliamo le colonne inutili e definiamo nomi colonne + df["sheet0"] = df["sheet0"].drop(["Unnamed: 6", "Unnamed: 7"], axis=1) + df["sheet0"].columns = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["colonne0"] + + if interface.DEBUGGENERAL: st.write(f"anno estratto: {anno_estratto}") + + try: + anno_estratto = df["sheet1"].iloc[self.DIZIONARIO[self.ANNO_RIFERIMENTO]["indirizzoAnno_1"]] + anno_estratto = anno_estratto[self.DIZIONARIO[self.ANNO_RIFERIMENTO]["indirizzoAnno_2"]] + except Exception as e: + st.error(f"Riscontrato un errore critico ({e}) - impossibile proseguire.") + st.error("CONTROLLARE CORRETTEZZA ANNO RIFERIMENTO!") + st.info("L'elaborazione e' stata interrotta") + st.stop() + if interface.DEBUGGENERAL: st.write(f"anno estratto: {anno_estratto}") + if str(anno_estratto) != str(self.ANNO_RIFERIMENTO): + st.warning(f"ATTENZIONE: l'anno contenuto nel file '{file_name}' ({anno_estratto}) non corrisponde all'anno di riferimento selezionato ({self.ANNO_RIFERIMENTO})!") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.info("L'elaborazione e' stata interrotta") + st.stop() + #return df + # può capitare che i colleghi scrivano nelle colonne a fianco di quelle che ci interessano + # e quindi eliminiamo le colonne oltre la decima (per anni 2019, 2020) + # e oltre la nona per anno 2021 + # cfr. DIZIONARIO + try: + dropAfterColumn = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["dropAfterColumn"] # la colonna dopo la quale eliminiamo le colonne + df["sheet1"] = df["sheet1"].drop(df["sheet1"].iloc[:, dropAfterColumn:], axis=1) + df["sheet1"].columns = self.DIZIONARIO[self.ANNO_RIFERIMENTO]["colonne1"] + except Exception as e: + st.error(f"Non e' stato possibile elaborare il file '{file_name}'") + st.error(f"Probabilmente e' stato scelto un anno riferimento sbagliato ({self.ANNO_RIFERIMENTO}) mentre il file contiene l'anno {anno_estratto}, quindi il file caricato non e' strutturato come previsto per l'anno scelto") + st.error(f"Errore riscontrato durante l'elaborazione: {e}") + if interface.TOLLERANZAZERO: st.stop() + return + + df = self.make_bool_columns(df) + + for a in (0, 1): + # ciclo da foglio 0 a foglio 1 + sheet = "sheet" + str(a) + + # estrazione nome microstruttura + microstruttura = df[sheet].iloc[1] + microstruttura = microstruttura[1] + if interface.DEBUGGENERAL: st.write("microstruttura = "+ str(microstruttura)) + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(microstruttura, str) + + if not res: + st.error( + f"Manca informazione MICROSTRUTTURA nel foglio {a+1} nel file --> {file_name}" + ) + microstruttura = "assente" + # settiamo flag bool + df[sheet]["dataErrMicrostruttura"] = True + if interface.TOLLERANZAZERO: st.stop() + + # estrazione nome ente + ente = df[sheet].iloc[2] + ente = ente[1] + # controlliamo che si tratti di una stringa, altrimenti errore + res = isinstance(ente, str) + if not res: + st.error(f"Manca informazione GESTORE nel foglio {a+1} nel file --> {file_name}") + ente = "assente" + # settiamo flag bool + df[sheet]["dataErrGestore"] = True + if interface.TOLLERANZAZERO: st.stop() + + # inseriamo microstruttura ed ente nel df per foglio elaborato + df[sheet].insert(0, "Microstruttura", microstruttura) + df[sheet].insert(0, "Ente", ente) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df[sheet].insert(0, "filename", file_name) + + # togliamo le prime 6 righe perché non servono più + df[sheet] = df[sheet].drop(labels=range(0, 6), axis=0) + + # selezioniamo soltanto record con un valore nel campo cognome + validi = df[sheet]["Cognome"].notna() + df[sheet] = df[sheet][validi] + + # i dati possono contenere valori data invalidi + # siccome trattiamo i dati in un df e definiamo la colonna come *datetime64* + # dobbiamo intercettare le date invalide + conditionInizio = pd.to_datetime(df[sheet]["DataInizio"], errors="coerce", dayfirst=True).isnull() + conditionFine = pd.to_datetime(df[sheet]["DataFine"], errors="coerce", dayfirst=True).isnull() + condition = conditionInizio | conditionFine + + # controlliamo se ci sono date invalide in dataFine e dataInizio + if not df[sheet][condition].empty: + expndr = st.expander(f"Trovati {len(df[sheet][condition])} errori formato data in foglio {a+1} del file --> {file_name}") + with expndr: + st.info("Errori nel formato della data inizio o data fine") + interface.make_grid( + df[sheet][condition].sort_values(by=["Cognome"]), + "errformatodate" + sheet + file_name, + ) + # settiamo la colonna bool + df[sheet].loc[condition, "errData"] = True + + # se restituiamo con la data invalida crea problemi in seguito + # quindi visto che abbiamo segnalato l'errore + # creiamo il df pulito + df[sheet] = df[sheet][~condition] + + # infine definiamo le colonne data come data + # tolto il formato perche' e' meglio non forzare il formato + + df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + df[sheet]["DataFine"] = pd.to_datetime(df[sheet]["DataFine"], dayfirst=True)#.dt.date #, format="%d.%m.%Y") + #df[sheet]["DataInizio"] = pd.to_datetime(df[sheet]["DataInizio"], format="%d.%m.%Y") + # sostituiamo valori nulli nella colonna nome con "manca nome" + df[sheet]['Nome'] = df[sheet]['Nome'].replace(np.nan,'Manca Nome') + + + + return df + + + def make_bool_columns(self, df): + # aggiungiamo le colonne bool per ogni errore/controllo che abbiamo definito in ERRORDICT + # ci serve per creare la tabella finale e per avere uno storico + for a in (0, 1): + sheet = "sheet" + str(a) + for chiave_errore in self.DIZIONARIO[self.ANNO_RIFERIMENTO]["ERRORDICT"].items(): + if interface.DEBUGGENERAL: st.write(chiave_errore) + df[sheet][chiave_errore[0]] = np.nan + df[sheet][chiave_errore[0]] = df[sheet][chiave_errore[0]].astype("boolean") + + return df + + def get_dfout(self): + dfout = self.dfout + return dfout + +if __name__ == "__main__": + flag = 0 + valori = valoriEtErrori() + interface = make_interface(valori.DIZIONARIO) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + caricaEtControlla(interface, valori.DIZIONARIO) + dfcompleto = caricaEtControlla.dfout + + if interface.DEBUGGENERAL: st.write(dfcompleto) + + errori = trova_errori(valori.DIZIONARIO, interface, dfcompleto) + #st.stop() + + #interface.make_tabs() + + + diff --git a/pages/CalcoloSomme.ipynb b/pages/CalcoloSomme.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..329686d1a03dbc7a7053d554dfd017994ed701b6 --- /dev/null +++ b/pages/CalcoloSomme.ipynb @@ -0,0 +1,6746 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "import copy\n", + "import openpyxl\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "#fn = \"JahresBericht_Ahrntal_2021.xlsx\"\n", + "fn = \"errori dopo modifica 2021 - Copy.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "afbfb93b", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "df = pd.read_excel(fn, sheet_name = 'ita',engine = 'openpyxl')#, skiprows = 8)\n", + "#df = pd.read_excel(fn,engine = 'openpyxl')#, skiprows = 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " #\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\",\n", + " #\"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2021\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6f06a836", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,\"Cognome e nome bambino\", df[\"Cognome\"] + ' ' + df[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b44721c6", + "metadata": {}, + "outputs": [], + "source": [ + "df.drop([\"Cognome\",\"Nome\"], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3bac24f2", + "metadata": {}, + "outputs": [], + "source": [ + "# df" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Casa Bimbo '" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "7e2e0f52", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = df.iloc[4]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "62c2a66b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Bolzano\n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale NaN\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 NaN\n", + "Ore totali rendicontate per il 2021 NaN\n", + "Name: 4, dtype: object" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "05d1e376", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = gemeinde[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "e4eca77c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Bolzano'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + "cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + "df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + "df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]\n", + "ddff = pd.DataFrame()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "eee9a6ec", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "ed99ae10", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "600803c2", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
81.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
6659.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "66 59.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 00:00:00 \n", + "66 2022-08-31 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132 \n", + "66 132 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "66 968.25 " + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "condizione1 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] >= pd.to_datetime(\"19.10.2020\", format=\"%d.%m.%Y\")\n", + "condizione2 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] < pd.to_datetime(\"22.10.2020\", format=\"%d.%m.%Y\")\n", + "df[condizione1 & condizione2]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "90008ae8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020',\n", + " 'Ore totali rendicontate per il 2021'],\n", + " dtype='object')" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2021" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "29ed03dd", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26365935.2521.25956.502021-01-012021-12-31
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01182605.500.00605.502021-01-012021-07-01
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0811084.000.0084.002021-02-192021-06-08
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03184690.0030.75720.752021-01-012021-07-03
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02365965.5022.50988.002021-01-012021-12-31
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17110462.500.00462.502021-09-132021-12-31
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-313651314.500.001314.502021-01-012021-12-31
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01117274.5039.00313.502021-09-062021-12-31
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06163592.0022.00614.002021-02-252021-08-06
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-023651269.7531.501301.252021-01-012021-12-31
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30151372.0020.00392.002021-03-022021-07-30
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171981010.5022.001032.502021-01-012021-07-17
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25176652.0030.00682.002021-01-012021-06-25
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29311940.500.00940.502021-02-242021-12-31
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-153651338.75110.001448.752021-01-012021-12-31
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28148575.500.00575.502021-01-012021-05-28
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31243812.2576.00888.252021-01-012021-08-31
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02183428.0020.00448.002021-01-012021-07-02
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02103474.5078.00552.502021-09-202021-12-31
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24236979.00110.001089.002021-01-012021-08-24
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-3189263.5058.50322.002021-10-042021-12-31
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31243806.500.00806.502021-01-012021-08-31
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-313651016.0060.001076.002021-01-012021-12-31
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02331616.000.00616.002021-02-042021-12-31
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-172695.000.0095.002021-12-062021-12-31
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31209488.0020.00508.002021-01-042021-07-31
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-3040140.000.00140.002021-11-222021-12-31
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31212587.7523.50611.252021-01-012021-07-31
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04216573.0020.00593.002021-01-012021-08-04
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-283651211.750.001211.752021-01-012021-12-31
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30211476.0020.00496.002021-01-012021-07-30
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27239469.5023.50493.002021-01-012021-08-27
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02306200.250.00200.252021-03-012021-12-31
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31243973.0095.001068.002021-01-012021-08-31
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01124493.5078.00571.502021-08-302021-12-31
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24236562.5022.50585.002021-01-012021-08-24
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16117427.250.00427.252021-09-062021-12-31
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06209950.7532.00982.752021-02-102021-09-06
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-313651405.0035.001440.002021-01-012021-12-31
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08281632.500.00632.502021-01-012021-10-08
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-0175248.250.00248.252021-10-182021-12-31
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-3082213.000.00213.002021-10-112021-12-31
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31124543.750.00543.752021-08-302021-12-31
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31221706.000.00706.002021-05-252021-12-31
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31212496.0020.00516.002021-01-012021-07-31
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-1754108.500.00108.502021-11-082021-12-31
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-043651353.2532.501385.752021-01-012021-12-31
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-313651643.50132.001775.502021-01-012021-12-31
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03246695.0063.00758.002021-01-012021-09-03
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10253879.5021.25900.752021-01-012021-09-10
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-0275276.000.00276.002021-10-182021-12-31
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-313651328.5025.001353.502021-01-012021-12-31
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30187543.000.00543.002021-06-282021-12-31
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01103401.500.00401.502021-09-202021-12-31
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-313651734.000.001734.002021-01-012021-12-31
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02124629.500.00629.502021-08-302021-12-31
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-263651152.5066.001218.502021-01-012021-12-31
66BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "66 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "66 2022-08-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 365 \n", + "10 182 \n", + "11 110 \n", + "12 184 \n", + "13 365 \n", + "14 110 \n", + "15 365 \n", + "16 117 \n", + "17 163 \n", + "18 365 \n", + "19 151 \n", + "20 198 \n", + "21 176 \n", + "22 311 \n", + "23 365 \n", + "24 148 \n", + "25 243 \n", + "26 183 \n", + "27 103 \n", + "28 236 \n", + "29 89 \n", + "30 243 \n", + "31 365 \n", + "32 331 \n", + "33 26 \n", + "34 209 \n", + "35 40 \n", + "36 212 \n", + "37 216 \n", + "38 365 \n", + "39 211 \n", + "40 239 \n", + "41 306 \n", + "42 243 \n", + "43 124 \n", + "44 236 \n", + "45 117 \n", + "46 209 \n", + "47 365 \n", + "48 281 \n", + "49 75 \n", + "50 82 \n", + "51 124 \n", + "52 221 \n", + "53 212 \n", + "54 54 \n", + "55 365 \n", + "56 365 \n", + "57 246 \n", + "58 253 \n", + "59 75 \n", + "60 365 \n", + "61 187 \n", + "62 103 \n", + "63 365 \n", + "64 124 \n", + "65 365 \n", + "66 365 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 968.25 2021-01-01 2021-12-31 \n", + "9 956.50 2021-01-01 2021-12-31 \n", + "10 605.50 2021-01-01 2021-07-01 \n", + "11 84.00 2021-02-19 2021-06-08 \n", + "12 720.75 2021-01-01 2021-07-03 \n", + "13 988.00 2021-01-01 2021-12-31 \n", + "14 462.50 2021-09-13 2021-12-31 \n", + "15 1314.50 2021-01-01 2021-12-31 \n", + "16 313.50 2021-09-06 2021-12-31 \n", + "17 614.00 2021-02-25 2021-08-06 \n", + "18 1301.25 2021-01-01 2021-12-31 \n", + "19 392.00 2021-03-02 2021-07-30 \n", + "20 1032.50 2021-01-01 2021-07-17 \n", + "21 682.00 2021-01-01 2021-06-25 \n", + "22 940.50 2021-02-24 2021-12-31 \n", + "23 1448.75 2021-01-01 2021-12-31 \n", + "24 575.50 2021-01-01 2021-05-28 \n", + "25 888.25 2021-01-01 2021-08-31 \n", + "26 448.00 2021-01-01 2021-07-02 \n", + "27 552.50 2021-09-20 2021-12-31 \n", + "28 1089.00 2021-01-01 2021-08-24 \n", + "29 322.00 2021-10-04 2021-12-31 \n", + "30 806.50 2021-01-01 2021-08-31 \n", + "31 1076.00 2021-01-01 2021-12-31 \n", + "32 616.00 2021-02-04 2021-12-31 \n", + "33 95.00 2021-12-06 2021-12-31 \n", + "34 508.00 2021-01-04 2021-07-31 \n", + "35 140.00 2021-11-22 2021-12-31 \n", + "36 611.25 2021-01-01 2021-07-31 \n", + "37 593.00 2021-01-01 2021-08-04 \n", + "38 1211.75 2021-01-01 2021-12-31 \n", + "39 496.00 2021-01-01 2021-07-30 \n", + "40 493.00 2021-01-01 2021-08-27 \n", + "41 200.25 2021-03-01 2021-12-31 \n", + "42 1068.00 2021-01-01 2021-08-31 \n", + "43 571.50 2021-08-30 2021-12-31 \n", + "44 585.00 2021-01-01 2021-08-24 \n", + "45 427.25 2021-09-06 2021-12-31 \n", + "46 982.75 2021-02-10 2021-09-06 \n", + "47 1440.00 2021-01-01 2021-12-31 \n", + "48 632.50 2021-01-01 2021-10-08 \n", + "49 248.25 2021-10-18 2021-12-31 \n", + "50 213.00 2021-10-11 2021-12-31 \n", + "51 543.75 2021-08-30 2021-12-31 \n", + "52 706.00 2021-05-25 2021-12-31 \n", + "53 516.00 2021-01-01 2021-07-31 \n", + "54 108.50 2021-11-08 2021-12-31 \n", + "55 1385.75 2021-01-01 2021-12-31 \n", + "56 1775.50 2021-01-01 2021-12-31 \n", + "57 758.00 2021-01-01 2021-09-03 \n", + "58 900.75 2021-01-01 2021-09-10 \n", + "59 276.00 2021-10-18 2021-12-31 \n", + "60 1353.50 2021-01-01 2021-12-31 \n", + "61 543.00 2021-06-28 2021-12-31 \n", + "62 401.50 2021-09-20 2021-12-31 \n", + "63 1734.00 2021-01-01 2021-12-31 \n", + "64 629.50 2021-08-30 2021-12-31 \n", + "65 1218.50 2021-01-01 2021-12-31 \n", + "66 968.25 2021-01-01 2021-12-31 " + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "id": "fcd45d79", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
8BAH MAMADOU ADAMA132.00
9TUCCIO GABRIEL21.25
10GAMBINO AMBRA0.00
11BISULTANOV MANSUR0.00
12DELVAI MATTEO30.75
13TOSI SOFIA22.50
14BRAHAJ SJORDI0.00
15BUCCELLA LORENZO0.00
16FIALCOVSCHI ALEXANDRU39.00
17CHIHI LISA22.00
18LANARI ARIANNA31.50
19PATRICELLI GIULIA20.00
20SMITH LIAM22.00
21CORNESCU DANIELE30.00
22SCARATTI FRANCESCA0.00
23BARDINI MARCO110.00
24DALL'ARMELLINA PIETRO0.00
25DE LUCIA MARTINA76.00
26DE PALMA ALESSANDRO20.00
27MOHAMMAD SALEEH BERITAN78.00
28PEREZZANI NOELLE110.00
29DI FEBBRAIO GIUSEPPE58.50
30DI PIERRO ALICE0.00
31DONOLA MATILDE60.00
32KHOUIA HIBA0.00
33KANOUNE MARYEM ELBATOUL0.00
34EL HAMDAOUI NIZAR20.00
35AYALA GALLEGOS JAYDEN0.00
36GASHI AMRA23.50
37SICOLO FRANCESCO20.00
38DI MARCO ANITA0.00
39HYSENAJ ESLI20.00
40BILAL SHAMIR23.50
41LLESHI DANIEL0.00
42LORENZINI MARINA95.00
43LOTIERZO NICOLO'78.00
44MIRA TEO22.50
45VENTURINI AURORA0.00
46MION GINEVRA32.00
47NEZA REAN35.00
48PEDINI LILIANA0.00
49PEREZ PONCE ELLIE0.00
50CIRILLO JACOPO0.00
51BAR NICHOLAS0.00
52CUEL MATAN0.00
53POPESCU MATEI20.00
54PASCARELLA DOMENICO0.00
55CAMPARETTO ROCCA EDOARDO32.50
56FIORE LEONARDO132.00
57DE COL BEATRICE63.00
58SOTA PAOLA21.25
59TATARI SAUL0.00
60TRINCO ANITA25.00
61VALLAZZA ISABEL0.00
62MANGIALAIO LEON0.00
63WEGLEITER ENEAS0.00
64SAID ZAYD0.00
65RINDONE FILIPPO TOMMASO66.00
66BAH MAMADOU ADAMA132.00
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino \\\n", + "8 BAH MAMADOU ADAMA \n", + "9 TUCCIO GABRIEL \n", + "10 GAMBINO AMBRA \n", + "11 BISULTANOV MANSUR \n", + "12 DELVAI MATTEO \n", + "13 TOSI SOFIA \n", + "14 BRAHAJ SJORDI \n", + "15 BUCCELLA LORENZO \n", + "16 FIALCOVSCHI ALEXANDRU \n", + "17 CHIHI LISA \n", + "18 LANARI ARIANNA \n", + "19 PATRICELLI GIULIA \n", + "20 SMITH LIAM \n", + "21 CORNESCU DANIELE \n", + "22 SCARATTI FRANCESCA \n", + "23 BARDINI MARCO \n", + "24 DALL'ARMELLINA PIETRO \n", + "25 DE LUCIA MARTINA \n", + "26 DE PALMA ALESSANDRO \n", + "27 MOHAMMAD SALEEH BERITAN \n", + "28 PEREZZANI NOELLE \n", + "29 DI FEBBRAIO GIUSEPPE \n", + "30 DI PIERRO ALICE \n", + "31 DONOLA MATILDE \n", + "32 KHOUIA HIBA \n", + "33 KANOUNE MARYEM ELBATOUL \n", + "34 EL HAMDAOUI NIZAR \n", + "35 AYALA GALLEGOS JAYDEN \n", + "36 GASHI AMRA \n", + "37 SICOLO FRANCESCO \n", + "38 DI MARCO ANITA \n", + "39 HYSENAJ ESLI \n", + "40 BILAL SHAMIR \n", + "41 LLESHI DANIEL \n", + "42 LORENZINI MARINA \n", + "43 LOTIERZO NICOLO' \n", + "44 MIRA TEO \n", + "45 VENTURINI AURORA \n", + "46 MION GINEVRA \n", + "47 NEZA REAN \n", + "48 PEDINI LILIANA \n", + "49 PEREZ PONCE ELLIE \n", + "50 CIRILLO JACOPO \n", + "51 BAR NICHOLAS \n", + "52 CUEL MATAN \n", + "53 POPESCU MATEI \n", + "54 PASCARELLA DOMENICO \n", + "55 CAMPARETTO ROCCA EDOARDO \n", + "56 FIORE LEONARDO \n", + "57 DE COL BEATRICE \n", + "58 SOTA PAOLA \n", + "59 TATARI SAUL \n", + "60 TRINCO ANITA \n", + "61 VALLAZZA ISABEL \n", + "62 MANGIALAIO LEON \n", + "63 WEGLEITER ENEAS \n", + "64 SAID ZAYD \n", + "65 RINDONE FILIPPO TOMMASO \n", + "66 BAH MAMADOU ADAMA \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 " + ] + }, + "execution_count": 177, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[[\"Cognome e nome bambino\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "8bae63ee", + "metadata": {}, + "outputs": [], + "source": [ + "#dfx = df[[\"Comune\", \"Cognome e nome bambino\",\"Codice fiscale\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"]]\n", + "dfout = pd.DataFrame(columns = [\"Comune\", \"Cognome e nome bambino\",\"Codice fiscale\", \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "342a6ed9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneCognome e nome bambinoCodice fiscaleOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Comune, Cognome e nome bambino, Codice fiscale, Ore contrattualizzate non erogate\n", + "ai sensi della delibera\n", + "n. 1025/2020]\n", + "Index: []" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 210, + "id": "75bbbfb7", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Bingo\n" + ] + } + ], + "source": [ + "for ind in df.index:\n", + " if df[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"][ind] > 0:\n", + " if dfout.empty:\n", + " dfout = df.loc[[ind]]\n", + " else:\n", + " if df[\"Codice fiscale\"][ind] in dfout[\"Codice fiscale\"].values:\n", + " print(\"Bingo\")\n", + " continue\n", + " dfout = pd.concat([dfout, df.loc[[ind]]])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 211, + "id": "ba1b8d2a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31365836.25132.00968.252021-01-012021-12-31
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26365935.2521.25956.502021-01-012021-12-31
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03184690.0030.75720.752021-01-012021-07-03
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02365965.5022.50988.002021-01-012021-12-31
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01117274.5039.00313.502021-09-062021-12-31
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06163592.0022.00614.002021-02-252021-08-06
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-023651269.7531.501301.252021-01-012021-12-31
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30151372.0020.00392.002021-03-022021-07-30
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171981010.5022.001032.502021-01-012021-07-17
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25176652.0030.00682.002021-01-012021-06-25
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-153651338.75110.001448.752021-01-012021-12-31
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31243812.2576.00888.252021-01-012021-08-31
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02183428.0020.00448.002021-01-012021-07-02
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02103474.5078.00552.502021-09-202021-12-31
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24236979.00110.001089.002021-01-012021-08-24
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-3189263.5058.50322.002021-10-042021-12-31
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-313651016.0060.001076.002021-01-012021-12-31
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31209488.0020.00508.002021-01-042021-07-31
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31212587.7523.50611.252021-01-012021-07-31
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04216573.0020.00593.002021-01-012021-08-04
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30211476.0020.00496.002021-01-012021-07-30
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27239469.5023.50493.002021-01-012021-08-27
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31243973.0095.001068.002021-01-012021-08-31
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01124493.5078.00571.502021-08-302021-12-31
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24236562.5022.50585.002021-01-012021-08-24
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06209950.7532.00982.752021-02-102021-09-06
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-313651405.0035.001440.002021-01-012021-12-31
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31212496.0020.00516.002021-01-012021-07-31
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-043651353.2532.501385.752021-01-012021-12-31
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-313651643.50132.001775.502021-01-012021-12-31
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03246695.0063.00758.002021-01-012021-09-03
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10253879.5021.25900.752021-01-012021-09-10
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-313651328.5025.001353.502021-01-012021-12-31
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-263651152.5066.001218.502021-01-012021-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "23 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "31 BOLZANO \n", + "34 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "53 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "60 BOLZANO \n", + "65 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "23 2020-08-17 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "31 2020-09-28 \n", + "34 2021-01-04 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "53 2020-06-01 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "60 2020-12-28 \n", + "65 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "23 2022-08-15 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "31 2022-08-31 \n", + "34 2021-07-31 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "53 2021-07-31 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "60 2023-08-31 \n", + "65 2022-08-26 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 365 \n", + "12 184 \n", + "13 365 \n", + "16 117 \n", + "17 163 \n", + "18 365 \n", + "19 151 \n", + "20 198 \n", + "21 176 \n", + "23 365 \n", + "25 243 \n", + "26 183 \n", + "27 103 \n", + "28 236 \n", + "29 89 \n", + "31 365 \n", + "34 209 \n", + "36 212 \n", + "37 216 \n", + "39 211 \n", + "40 239 \n", + "42 243 \n", + "43 124 \n", + "44 236 \n", + "46 209 \n", + "47 365 \n", + "53 212 \n", + "55 365 \n", + "56 365 \n", + "57 246 \n", + "58 253 \n", + "60 365 \n", + "65 365 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "12 690.00 \n", + "13 965.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "23 1338.75 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "31 1016.00 \n", + "34 488.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "39 476.00 \n", + "40 469.50 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "46 950.75 \n", + "47 1405.00 \n", + "53 496.00 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "60 1328.50 \n", + "65 1152.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "12 30.75 \n", + "13 22.50 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "23 110.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "31 60.00 \n", + "34 20.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "46 32.00 \n", + "47 35.00 \n", + "53 20.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "60 25.00 \n", + "65 66.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 968.25 2021-01-01 2021-12-31 \n", + "9 956.50 2021-01-01 2021-12-31 \n", + "12 720.75 2021-01-01 2021-07-03 \n", + "13 988.00 2021-01-01 2021-12-31 \n", + "16 313.50 2021-09-06 2021-12-31 \n", + "17 614.00 2021-02-25 2021-08-06 \n", + "18 1301.25 2021-01-01 2021-12-31 \n", + "19 392.00 2021-03-02 2021-07-30 \n", + "20 1032.50 2021-01-01 2021-07-17 \n", + "21 682.00 2021-01-01 2021-06-25 \n", + "23 1448.75 2021-01-01 2021-12-31 \n", + "25 888.25 2021-01-01 2021-08-31 \n", + "26 448.00 2021-01-01 2021-07-02 \n", + "27 552.50 2021-09-20 2021-12-31 \n", + "28 1089.00 2021-01-01 2021-08-24 \n", + "29 322.00 2021-10-04 2021-12-31 \n", + "31 1076.00 2021-01-01 2021-12-31 \n", + "34 508.00 2021-01-04 2021-07-31 \n", + "36 611.25 2021-01-01 2021-07-31 \n", + "37 593.00 2021-01-01 2021-08-04 \n", + "39 496.00 2021-01-01 2021-07-30 \n", + "40 493.00 2021-01-01 2021-08-27 \n", + "42 1068.00 2021-01-01 2021-08-31 \n", + "43 571.50 2021-08-30 2021-12-31 \n", + "44 585.00 2021-01-01 2021-08-24 \n", + "46 982.75 2021-02-10 2021-09-06 \n", + "47 1440.00 2021-01-01 2021-12-31 \n", + "53 516.00 2021-01-01 2021-07-31 \n", + "55 1385.75 2021-01-01 2021-12-31 \n", + "56 1775.50 2021-01-01 2021-12-31 \n", + "57 758.00 2021-01-01 2021-09-03 \n", + "58 900.75 2021-01-01 2021-09-10 \n", + "60 1353.50 2021-01-01 2021-12-31 \n", + "65 1218.50 2021-01-01 2021-12-31 " + ] + }, + "execution_count": 211, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "98dadca8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021inizioNormfineNorm
8Ajardi Josef0Ahrntal2019-10-02JRDJSF19R02B220YKirchler JudithSt. Peter In Ahrntal2020-02-242022-08-313651056.2524.001080.252021-01-012021-12-31
9Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-09-142020-12-3105.500.005.502021-01-012020-12-31
10Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-09-172021-06-29180289.5012.00301.502021-01-012021-06-29
11Eder Nicolas Adele0Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2021-09-062022-06-30117260.250.00260.252021-09-062021-12-31
12Feichter Robin0Ahrntal2019-08-27FCHRBN19M27B220NKammerlander VerenaAhrntal2021-10-192021-11-112415.250.0015.252021-10-192021-11-11
13Forer Mattis0Ahrntal2018-11-27FRRMTS18S27B220AKirchler IrmgardAhrntal2021-01-192021-08-31225287.258.00295.252021-01-192021-08-31
14Hofer Hanna0Ahrntal2018-09-05HFRHNN18P45B220DKirchler IrmgardAhrntal2020-09-142021-08-27239500.250.00500.252021-01-012021-08-27
15Hofer Julian0Ahrntal2020-04-16HFRJLN20D16B220PKirchler IrmgardAhrntal2020-08-132022-01-143651305.7522.001327.752021-01-012021-12-31
16Hofer Lukas0Ahrntal2019-05-31HFRLKS19E31B220NKirchler JudithSt. Peter In Ahrntal2021-11-172022-04-214550.250.0050.252021-11-172021-12-31
17Hopfgartner Toni0Ahrntal2018-01-31HPFTNO18A31B220PKammerlander VerenaAhrntal2019-02-112021-08-31243404.7516.00420.752021-01-012021-08-31
18Innerbichler Greta0Ahrntal2019-11-21NNRGRT19S61B220GKammerlander VerenaAhrntal2021-11-232020-12-31-32669.500.0069.502021-11-232020-12-31
19Innerbichler Jona0Ahrntal2019-06-03NNRJNO19H03B220WKirchler IrmgardAhrntal2021-11-022022-01-136073.000.0073.002021-11-022021-12-31
20Innerbichler Simon0Ahrntal2018-06-24NNRSMN18H24B220FKirchler JudithSt. Peter In Ahrntal2019-08-202021-09-06249756.0027.00783.002021-01-012021-09-06
21Kirchler Isabel0Ahrntal2018-02-07KRCSBL18B47B220NKammerlander VerenaAhrntal2019-01-022021-08-31243316.0012.00328.002021-01-012021-08-31
22Kirchler Lea Sophie0Ahrntal2020-02-29KRCLPH20B69B220IKirchler IrmgardAhrntal2021-09-082021-12-22106176.750.00176.752021-09-082021-12-22
23Lechner Lisa0Ahrntal2018-06-09LCHLSI18H49B220JKirchler ClaudiaSt. Jakob in Ahrntal2020-07-012021-08-31243347.5012.00359.502021-01-012021-08-31
24Mittermair Samu0Ahrntal2020-04-07MTTSMA20D07B220VKammerlander VerenaAhrntal2021-03-162020-12-31-74431.250.00431.252021-03-162020-12-31
25Niederwanger Liah0Ahrntal2020-02-23NDRLHI20B63B220QKammerlander VerenaAhrntal2021-09-062020-12-31-248155.250.00155.252021-09-062020-12-31
26Oberhauser Anton0Ahrntal2018-05-13BRHNTN18E13B220EKirchler IrmgardAhrntal2020-09-092021-08-31243735.000.00735.002021-01-012021-08-31
27Oberhofer Greta0Ahrntal2018-11-09BRHGRT18S49B220RKammerlander VerenaAhrntal2019-12-022021-08-31243364.0014.00378.002021-01-012021-08-31
28Oberlechner Emilia0Ahrntal2018-09-14BRLMLE18P54B220XKammerlander VerenaAhrntal2020-01-082021-08-31243599.5024.00623.502021-01-012021-08-31
29Obermair Theresa0Ahrntal2019-06-06BRMTRS19H46A952AKirchler JudithSt. Peter In Ahrntal2020-10-022022-08-30365863.0018.00881.002021-01-012021-12-31
30Obermair Tommi Jona0Ahrntal2019-06-07BRMTMJ19H07B220DKirchler ClaudiaSt. Jakob in Ahrntal2020-09-142020-12-310610.7512.00622.752021-01-012020-12-31
31Oberschmied Matilda0Ahrntal2019-08-07BRSMLD19M47B220BKirchler ClaudiaSt. Jakob in Ahrntal2020-09-092020-12-310884.000.00884.002021-01-012020-12-31
32Pareiner Jakob0Ahrntal2019-07-31PRNJKB19L31B220ZKirchler IrmgardAhrntal2020-10-052022-01-14365695.250.00695.252021-01-012021-12-31
33Ploner Greti0Ahrntal2018-04-23PLNGRT18D63B220AKirchler IrmgardAhrntal2019-08-192021-08-27239931.5010.50942.002021-01-012021-08-27
34Seeber Benjamin0Ahrntal2020-01-01SBRBJM20A01B220SKirchler IrmgardAhrntal2021-09-012021-12-22113250.000.00250.002021-09-012021-12-22
35Steger Elias0Ahrntal2018-03-19STGLSE18C19B220NKirchler IrmgardAhrntal2019-07-192021-08-26238601.5020.00621.502021-01-012021-08-26
36Steger Maximilian0Ahrntal2020-06-10STGMML20H10B220QKirchler ClaudiaSt. Jakob in Ahrntal2021-06-212020-12-31-171311.500.00311.502021-06-212020-12-31
37Steger Romy0Ahrntal2019-11-18STGRMY19S58B220DKirchler ClaudiaSt. Jakob in Ahrntal2021-05-112021-06-224354.750.0054.752021-05-112021-06-22
38Stolzlechner Clara0Ahrntal2018-01-02STLCLR18A42B220HKirchler JudithSt. Peter In Ahrntal2019-01-092021-09-06249553.2520.25573.502021-01-012021-09-06
39Timillero Liliane Giovanna0Ahrntal2021-04-15TMLLNG21D55B220DKammerlander VerenaAhrntal2021-09-062020-12-31-248220.750.00220.752021-09-062020-12-31
40Weger Maximilian0Ahrntal2020-06-24WGRMML20H24B220PKirchler ClaudiaSt. Jakob in Ahrntal2021-03-152020-12-31-73545.750.00545.752021-03-152020-12-31
41Weger Maximilian0Ahrntal2020-06-24WGRMML20H24B220PKirchler ClaudiaSt. Jakob in Ahrntal2021-09-062020-12-31-248190.750.00190.752021-09-062020-12-31
42Zimmerhofer Lio0Ahrntal2020-02-25ZMMLIO20B25Z102RKirchler IrmgardAhrntal2021-09-142021-12-23101165.500.00165.502021-09-142021-12-23
43Zimmerhofer Maja0Ahrntal2019-09-18ZMMMJA19P58B220BKirchler IrmgardAhrntal2021-08-112021-10-227397.500.0097.502021-08-112021-10-22
44Zoeschg Luzia0Ahrntal2020-05-09ZSCLZU20E49B220SKirchler JudithSt. Peter In Ahrntal2021-03-222020-12-31-80576.500.00576.502021-03-222020-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 Ajardi Josef 0 Ahrntal 2019-10-02 \n", + "9 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "10 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "11 Eder Nicolas Adele 0 Ahrntal 2019-01-06 \n", + "12 Feichter Robin 0 Ahrntal 2019-08-27 \n", + "13 Forer Mattis 0 Ahrntal 2018-11-27 \n", + "14 Hofer Hanna 0 Ahrntal 2018-09-05 \n", + "15 Hofer Julian 0 Ahrntal 2020-04-16 \n", + "16 Hofer Lukas 0 Ahrntal 2019-05-31 \n", + "17 Hopfgartner Toni 0 Ahrntal 2018-01-31 \n", + "18 Innerbichler Greta 0 Ahrntal 2019-11-21 \n", + "19 Innerbichler Jona 0 Ahrntal 2019-06-03 \n", + "20 Innerbichler Simon 0 Ahrntal 2018-06-24 \n", + "21 Kirchler Isabel 0 Ahrntal 2018-02-07 \n", + "22 Kirchler Lea Sophie 0 Ahrntal 2020-02-29 \n", + "23 Lechner Lisa 0 Ahrntal 2018-06-09 \n", + "24 Mittermair Samu 0 Ahrntal 2020-04-07 \n", + "25 Niederwanger Liah 0 Ahrntal 2020-02-23 \n", + "26 Oberhauser Anton 0 Ahrntal 2018-05-13 \n", + "27 Oberhofer Greta 0 Ahrntal 2018-11-09 \n", + "28 Oberlechner Emilia 0 Ahrntal 2018-09-14 \n", + "29 Obermair Theresa 0 Ahrntal 2019-06-06 \n", + "30 Obermair Tommi Jona 0 Ahrntal 2019-06-07 \n", + "31 Oberschmied Matilda 0 Ahrntal 2019-08-07 \n", + "32 Pareiner Jakob 0 Ahrntal 2019-07-31 \n", + "33 Ploner Greti 0 Ahrntal 2018-04-23 \n", + "34 Seeber Benjamin 0 Ahrntal 2020-01-01 \n", + "35 Steger Elias 0 Ahrntal 2018-03-19 \n", + "36 Steger Maximilian 0 Ahrntal 2020-06-10 \n", + "37 Steger Romy 0 Ahrntal 2019-11-18 \n", + "38 Stolzlechner Clara 0 Ahrntal 2018-01-02 \n", + "39 Timillero Liliane Giovanna 0 Ahrntal 2021-04-15 \n", + "40 Weger Maximilian 0 Ahrntal 2020-06-24 \n", + "41 Weger Maximilian 0 Ahrntal 2020-06-24 \n", + "42 Zimmerhofer Lio 0 Ahrntal 2020-02-25 \n", + "43 Zimmerhofer Maja 0 Ahrntal 2019-09-18 \n", + "44 Zoeschg Luzia 0 Ahrntal 2020-05-09 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 JRDJSF19R02B220Y Kirchler Judith \n", + "9 DRNDLA19A46Z131E Kirchler Claudia \n", + "10 DRNDLA19A46Z131E Kirchler Claudia \n", + "11 DRNDLA19A46Z131E Kirchler Claudia \n", + "12 FCHRBN19M27B220N Kammerlander Verena \n", + "13 FRRMTS18S27B220A Kirchler Irmgard \n", + "14 HFRHNN18P45B220D Kirchler Irmgard \n", + "15 HFRJLN20D16B220P Kirchler Irmgard \n", + "16 HFRLKS19E31B220N Kirchler Judith \n", + "17 HPFTNO18A31B220P Kammerlander Verena \n", + "18 NNRGRT19S61B220G Kammerlander Verena \n", + "19 NNRJNO19H03B220W Kirchler Irmgard \n", + "20 NNRSMN18H24B220F Kirchler Judith \n", + "21 KRCSBL18B47B220N Kammerlander Verena \n", + "22 KRCLPH20B69B220I Kirchler Irmgard \n", + "23 LCHLSI18H49B220J Kirchler Claudia \n", + "24 MTTSMA20D07B220V Kammerlander Verena \n", + "25 NDRLHI20B63B220Q Kammerlander Verena \n", + "26 BRHNTN18E13B220E Kirchler Irmgard \n", + "27 BRHGRT18S49B220R Kammerlander Verena \n", + "28 BRLMLE18P54B220X Kammerlander Verena \n", + "29 BRMTRS19H46A952A Kirchler Judith \n", + "30 BRMTMJ19H07B220D Kirchler Claudia \n", + "31 BRSMLD19M47B220B Kirchler Claudia \n", + "32 PRNJKB19L31B220Z Kirchler Irmgard \n", + "33 PLNGRT18D63B220A Kirchler Irmgard \n", + "34 SBRBJM20A01B220S Kirchler Irmgard \n", + "35 STGLSE18C19B220N Kirchler Irmgard \n", + "36 STGMML20H10B220Q Kirchler Claudia \n", + "37 STGRMY19S58B220D Kirchler Claudia \n", + "38 STLCLR18A42B220H Kirchler Judith \n", + "39 TMLLNG21D55B220D Kammerlander Verena \n", + "40 WGRMML20H24B220P Kirchler Claudia \n", + "41 WGRMML20H24B220P Kirchler Claudia \n", + "42 ZMMLIO20B25Z102R Kirchler Irmgard \n", + "43 ZMMMJA19P58B220B Kirchler Irmgard \n", + "44 ZSCLZU20E49B220S Kirchler Judith \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 St. Peter In Ahrntal \n", + "9 St. Jakob in Ahrntal \n", + "10 St. Jakob in Ahrntal \n", + "11 St. Jakob in Ahrntal \n", + "12 Ahrntal \n", + "13 Ahrntal \n", + "14 Ahrntal \n", + "15 Ahrntal \n", + "16 St. Peter In Ahrntal \n", + "17 Ahrntal \n", + "18 Ahrntal \n", + "19 Ahrntal \n", + "20 St. Peter In Ahrntal \n", + "21 Ahrntal \n", + "22 Ahrntal \n", + "23 St. Jakob in Ahrntal \n", + "24 Ahrntal \n", + "25 Ahrntal \n", + "26 Ahrntal \n", + "27 Ahrntal \n", + "28 Ahrntal \n", + "29 St. Peter In Ahrntal \n", + "30 St. Jakob in Ahrntal \n", + "31 St. Jakob in Ahrntal \n", + "32 Ahrntal \n", + "33 Ahrntal \n", + "34 Ahrntal \n", + "35 Ahrntal \n", + "36 St. Jakob in Ahrntal \n", + "37 St. Jakob in Ahrntal \n", + "38 St. Peter In Ahrntal \n", + "39 Ahrntal \n", + "40 St. Jakob in Ahrntal \n", + "41 St. Jakob in Ahrntal \n", + "42 Ahrntal \n", + "43 Ahrntal \n", + "44 St. Peter In Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-02-24 \n", + "9 2020-09-14 \n", + "10 2020-09-17 \n", + "11 2021-09-06 \n", + "12 2021-10-19 \n", + "13 2021-01-19 \n", + "14 2020-09-14 \n", + "15 2020-08-13 \n", + "16 2021-11-17 \n", + "17 2019-02-11 \n", + "18 2021-11-23 \n", + "19 2021-11-02 \n", + "20 2019-08-20 \n", + "21 2019-01-02 \n", + "22 2021-09-08 \n", + "23 2020-07-01 \n", + "24 2021-03-16 \n", + "25 2021-09-06 \n", + "26 2020-09-09 \n", + "27 2019-12-02 \n", + "28 2020-01-08 \n", + "29 2020-10-02 \n", + "30 2020-09-14 \n", + "31 2020-09-09 \n", + "32 2020-10-05 \n", + "33 2019-08-19 \n", + "34 2021-09-01 \n", + "35 2019-07-19 \n", + "36 2021-06-21 \n", + "37 2021-05-11 \n", + "38 2019-01-09 \n", + "39 2021-09-06 \n", + "40 2021-03-15 \n", + "41 2021-09-06 \n", + "42 2021-09-14 \n", + "43 2021-08-11 \n", + "44 2021-03-22 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2020-12-31 \n", + "10 2021-06-29 \n", + "11 2022-06-30 \n", + "12 2021-11-11 \n", + "13 2021-08-31 \n", + "14 2021-08-27 \n", + "15 2022-01-14 \n", + "16 2022-04-21 \n", + "17 2021-08-31 \n", + "18 2020-12-31 \n", + "19 2022-01-13 \n", + "20 2021-09-06 \n", + "21 2021-08-31 \n", + "22 2021-12-22 \n", + "23 2021-08-31 \n", + "24 2020-12-31 \n", + "25 2020-12-31 \n", + "26 2021-08-31 \n", + "27 2021-08-31 \n", + "28 2021-08-31 \n", + "29 2022-08-30 \n", + "30 2020-12-31 \n", + "31 2020-12-31 \n", + "32 2022-01-14 \n", + "33 2021-08-27 \n", + "34 2021-12-22 \n", + "35 2021-08-26 \n", + "36 2020-12-31 \n", + "37 2021-06-22 \n", + "38 2021-09-06 \n", + "39 2020-12-31 \n", + "40 2020-12-31 \n", + "41 2020-12-31 \n", + "42 2021-12-23 \n", + "43 2021-10-22 \n", + "44 2020-12-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 365 \n", + "9 0 \n", + "10 180 \n", + "11 117 \n", + "12 24 \n", + "13 225 \n", + "14 239 \n", + "15 365 \n", + "16 45 \n", + "17 243 \n", + "18 -326 \n", + "19 60 \n", + "20 249 \n", + "21 243 \n", + "22 106 \n", + "23 243 \n", + "24 -74 \n", + "25 -248 \n", + "26 243 \n", + "27 243 \n", + "28 243 \n", + "29 365 \n", + "30 0 \n", + "31 0 \n", + "32 365 \n", + "33 239 \n", + "34 113 \n", + "35 238 \n", + "36 -171 \n", + "37 43 \n", + "38 249 \n", + "39 -248 \n", + "40 -73 \n", + "41 -248 \n", + "42 101 \n", + "43 73 \n", + "44 -80 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1056.25 \n", + "9 5.50 \n", + "10 289.50 \n", + "11 260.25 \n", + "12 15.25 \n", + "13 287.25 \n", + "14 500.25 \n", + "15 1305.75 \n", + "16 50.25 \n", + "17 404.75 \n", + "18 69.50 \n", + "19 73.00 \n", + "20 756.00 \n", + "21 316.00 \n", + "22 176.75 \n", + "23 347.50 \n", + "24 431.25 \n", + "25 155.25 \n", + "26 735.00 \n", + "27 364.00 \n", + "28 599.50 \n", + "29 863.00 \n", + "30 610.75 \n", + "31 884.00 \n", + "32 695.25 \n", + "33 931.50 \n", + "34 250.00 \n", + "35 601.50 \n", + "36 311.50 \n", + "37 54.75 \n", + "38 553.25 \n", + "39 220.75 \n", + "40 545.75 \n", + "41 190.75 \n", + "42 165.50 \n", + "43 97.50 \n", + "44 576.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 24.00 \n", + "9 0.00 \n", + "10 12.00 \n", + "11 0.00 \n", + "12 0.00 \n", + "13 8.00 \n", + "14 0.00 \n", + "15 22.00 \n", + "16 0.00 \n", + "17 16.00 \n", + "18 0.00 \n", + "19 0.00 \n", + "20 27.00 \n", + "21 12.00 \n", + "22 0.00 \n", + "23 12.00 \n", + "24 0.00 \n", + "25 0.00 \n", + "26 0.00 \n", + "27 14.00 \n", + "28 24.00 \n", + "29 18.00 \n", + "30 12.00 \n", + "31 0.00 \n", + "32 0.00 \n", + "33 10.50 \n", + "34 0.00 \n", + "35 20.00 \n", + "36 0.00 \n", + "37 0.00 \n", + "38 20.25 \n", + "39 0.00 \n", + "40 0.00 \n", + "41 0.00 \n", + "42 0.00 \n", + "43 0.00 \n", + "44 0.00 \n", + "\n", + " Ore totali rendicontate per il 2021 inizioNorm fineNorm \n", + "8 1080.25 2021-01-01 2021-12-31 \n", + "9 5.50 2021-01-01 2020-12-31 \n", + "10 301.50 2021-01-01 2021-06-29 \n", + "11 260.25 2021-09-06 2021-12-31 \n", + "12 15.25 2021-10-19 2021-11-11 \n", + "13 295.25 2021-01-19 2021-08-31 \n", + "14 500.25 2021-01-01 2021-08-27 \n", + "15 1327.75 2021-01-01 2021-12-31 \n", + "16 50.25 2021-11-17 2021-12-31 \n", + "17 420.75 2021-01-01 2021-08-31 \n", + "18 69.50 2021-11-23 2020-12-31 \n", + "19 73.00 2021-11-02 2021-12-31 \n", + "20 783.00 2021-01-01 2021-09-06 \n", + "21 328.00 2021-01-01 2021-08-31 \n", + "22 176.75 2021-09-08 2021-12-22 \n", + "23 359.50 2021-01-01 2021-08-31 \n", + "24 431.25 2021-03-16 2020-12-31 \n", + "25 155.25 2021-09-06 2020-12-31 \n", + "26 735.00 2021-01-01 2021-08-31 \n", + "27 378.00 2021-01-01 2021-08-31 \n", + "28 623.50 2021-01-01 2021-08-31 \n", + "29 881.00 2021-01-01 2021-12-31 \n", + "30 622.75 2021-01-01 2020-12-31 \n", + "31 884.00 2021-01-01 2020-12-31 \n", + "32 695.25 2021-01-01 2021-12-31 \n", + "33 942.00 2021-01-01 2021-08-27 \n", + "34 250.00 2021-09-01 2021-12-22 \n", + "35 621.50 2021-01-01 2021-08-26 \n", + "36 311.50 2021-06-21 2020-12-31 \n", + "37 54.75 2021-05-11 2021-06-22 \n", + "38 573.50 2021-01-01 2021-09-06 \n", + "39 220.75 2021-09-06 2020-12-31 \n", + "40 545.75 2021-03-15 2020-12-31 \n", + "41 190.75 2021-09-06 2020-12-31 \n", + "42 165.50 2021-09-14 2021-12-23 \n", + "43 97.50 2021-08-11 2021-10-22 \n", + "44 576.50 2021-03-22 2020-12-31 " + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ffeecee", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "3e8abe8d", + "metadata": {}, + "source": [ + "## Vecchio metodo" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "4acf4374", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre di assistenza \\n ai sensi della delibera\\nn. 666/2019
0Bolzano59
\n", + "
" + ], + "text/plain": [ + " Comune Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\n", + "0 Bolzano 59 " + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.groupby(\"Comune\", as_index=False)[\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\"\n", + " ].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "cdd9c198", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019
Comune
Bolzano59
\n", + "
" + ], + "text/plain": [ + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\n", + "Comune \n", + "Bolzano 59 " + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.groupby([\"Comune\"]).agg({\"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\":\"count\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "id": "71b02919", + "metadata": {}, + "outputs": [], + "source": [ + "#c = df[\"Codice fiscale\"].unique\n", + "dfx = df.drop_duplicates(subset = [\"Codice fiscale\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "id": "ea1a0a2d", + "metadata": {}, + "outputs": [], + "source": [ + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0" + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "id": "0db71170", + "metadata": {}, + "outputs": [], + "source": [ + " df2bis = dfx[c].groupby(\"Comune\", as_index=False)[\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"\n", + " ].apply(lambda x: x[x > 0].sum())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "634575da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
0Bolzano1612.75
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Bolzano \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \n", + "0 1612.75 " + ] + }, + "execution_count": 223, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2bis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "129075cb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 207, + "id": "8e1896c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "34" + ] + }, + "execution_count": 207, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#dfx = df.groupby(\"Codice fiscale\", as_index = False)\n", + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0\n", + "len(dfx[c])" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "id": "2d98620d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26935.2521.25956.50
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01605.500.00605.50
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0884.000.0084.00
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03690.0030.75720.75
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02965.5022.50988.00
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17462.500.00462.50
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-311314.500.001314.50
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01274.5039.00313.50
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06592.0022.00614.00
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-021269.7531.501301.25
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30372.0020.00392.00
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171010.5022.001032.50
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25652.0030.00682.00
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29940.500.00940.50
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-151338.75110.001448.75
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28575.500.00575.50
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31812.2576.00888.25
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02428.0020.00448.00
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02474.5078.00552.50
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24979.00110.001089.00
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-31263.5058.50322.00
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31806.500.00806.50
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-311016.0060.001076.00
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02616.000.00616.00
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-1795.000.0095.00
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31488.0020.00508.00
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-30140.000.00140.00
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31587.7523.50611.25
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04573.0020.00593.00
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-281211.750.001211.75
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30476.0020.00496.00
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27469.5023.50493.00
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02200.250.00200.25
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31973.0095.001068.00
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01493.5078.00571.50
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24562.5022.50585.00
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16427.250.00427.25
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06950.7532.00982.75
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-311405.0035.001440.00
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08632.500.00632.50
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-01248.250.00248.25
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-30213.000.00213.00
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31543.750.00543.75
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31706.000.00706.00
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31496.0020.00516.00
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-17108.500.00108.50
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-041353.2532.501385.75
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-311643.50132.001775.50
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03695.0063.00758.00
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10879.5021.25900.75
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-02276.000.00276.00
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-311328.5025.001353.50
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30543.000.00543.00
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01401.500.00401.50
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-311734.000.001734.00
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02629.500.00629.50
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-261152.5066.001218.50
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "9 956.50 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 720.75 \n", + "13 988.00 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 313.50 \n", + "17 614.00 \n", + "18 1301.25 \n", + "19 392.00 \n", + "20 1032.50 \n", + "21 682.00 \n", + "22 940.50 \n", + "23 1448.75 \n", + "24 575.50 \n", + "25 888.25 \n", + "26 448.00 \n", + "27 552.50 \n", + "28 1089.00 \n", + "29 322.00 \n", + "30 806.50 \n", + "31 1076.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 508.00 \n", + "35 140.00 \n", + "36 611.25 \n", + "37 593.00 \n", + "38 1211.75 \n", + "39 496.00 \n", + "40 493.00 \n", + "41 200.25 \n", + "42 1068.00 \n", + "43 571.50 \n", + "44 585.00 \n", + "45 427.25 \n", + "46 982.75 \n", + "47 1440.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 516.00 \n", + "54 108.50 \n", + "55 1385.75 \n", + "56 1775.50 \n", + "57 758.00 \n", + "58 900.75 \n", + "59 276.00 \n", + "60 1353.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1218.50 " + ] + }, + "execution_count": 202, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "a0f879dc", + "metadata": {}, + "outputs": [], + "source": [ + "df2 = df[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"].notnull()\n", + "df2 = df[c].groupby(\"Comune\", as_index = False)[\"Codice fiscale\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "7fb21c72", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneCodice fiscale
0Bolzano34
\n", + "
" + ], + "text/plain": [ + " Comune Codice fiscale\n", + "0 Bolzano 34" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38880426", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Casa Bimbo/Report annuale - BRENNERO.xlsx b/pages/Casa Bimbo/Report annuale - BRENNERO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8d1e3a69991b729c9893b269acce0f7eb44f5182 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - BRENNERO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale - BRONZOLO.xlsx b/pages/Casa Bimbo/Report annuale - BRONZOLO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ba1076005b5aa92b0512fea49328bcacaef92378 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - BRONZOLO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale - MARLENGO.xlsx b/pages/Casa Bimbo/Report annuale - MARLENGO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6de15cbb2f2d936edda74008a035a8aeffaa8aa2 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - MARLENGO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale - MERANO.xlsx b/pages/Casa Bimbo/Report annuale - MERANO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9c307e0381ec62def3d8dbaa806d1e3d96796f63 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - MERANO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale - MONTAGNA.xlsx b/pages/Casa Bimbo/Report annuale - MONTAGNA.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..acc1e8a36b307e84338c9582fa27df525fcc434a Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - MONTAGNA.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale - SALORNO.xlsx b/pages/Casa Bimbo/Report annuale - SALORNO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..36b00170184912d9d4195c2762f65f089d5ce21f Binary files /dev/null and b/pages/Casa Bimbo/Report annuale - SALORNO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale -ORA.xlsx b/pages/Casa Bimbo/Report annuale -ORA.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..11205888dce63a9b94e874675b46105c1579df33 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale -ORA.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale -VIPITENO.xlsx b/pages/Casa Bimbo/Report annuale -VIPITENO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8d9851b0d4a70fd08c6a27ad0e9a793da5343921 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale -VIPITENO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale BOLZANO.xlsx b/pages/Casa Bimbo/Report annuale BOLZANO.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..993b2a398fb4bda1c88b66797c5f2a1a94123db0 Binary files /dev/null and b/pages/Casa Bimbo/Report annuale BOLZANO.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale EGNA.xlsx b/pages/Casa Bimbo/Report annuale EGNA.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..959958d1fc66696f3cc8688f9fa25a90f4229c2b Binary files /dev/null and b/pages/Casa Bimbo/Report annuale EGNA.xlsx differ diff --git a/pages/Casa Bimbo/Report annuale LAIVES.xlsx b/pages/Casa Bimbo/Report annuale LAIVES.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..64c9980a4370a282c5d68ddf3fa561ddb9636caf Binary files /dev/null and b/pages/Casa Bimbo/Report annuale LAIVES.xlsx differ diff --git a/pages/DejaVuSans-Bold.ttf b/pages/DejaVuSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..328fdb2aa4a7e67977769f2d4bcd8b187b50a76a --- /dev/null +++ b/pages/DejaVuSans-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6476c1b80502924294eed40894c5b18e06c181444ca953e5334262df9c27724 +size 705684 diff --git a/pages/DejaVuSans-BoldOblique.ttf b/pages/DejaVuSans-BoldOblique.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f7fd1f042ff8828330e0ac6e0c65afc22eb4dcaa --- /dev/null +++ b/pages/DejaVuSans-BoldOblique.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb436dca0c2594b73d8b603b892e374fdfd8d885d25ffb4f18df4c4c0b49e50f +size 643292 diff --git a/pages/DejaVuSans-ExtraLight.ttf b/pages/DejaVuSans-ExtraLight.ttf new file mode 100644 index 0000000000000000000000000000000000000000..575362c1cb60b7be5ce32a79cf582d19b27c4b16 --- /dev/null +++ b/pages/DejaVuSans-ExtraLight.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6cb0746a1f68d176bebe83752cee35ebdf726cb1a1e88a01fc038ddf76de9ea8 +size 355380 diff --git a/pages/DejaVuSans-Oblique.ttf b/pages/DejaVuSans-Oblique.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d36f4177d3295256abaef33142c739678c2fcb8d --- /dev/null +++ b/pages/DejaVuSans-Oblique.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4af75fa16ee6d3ad43e1ecec41862c24954af26a55c6bb1ebb27bd486a50f5f4 +size 635416 diff --git a/pages/DejaVuSans.ttf b/pages/DejaVuSans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..356575d14731ad077bde1fb0aac44f88bb51f5c4 --- /dev/null +++ b/pages/DejaVuSans.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7da195a74c55bef988d0d48f9508bd5d849425c1770dba5d7bfc6ce9ed848954 +size 757076 diff --git a/pages/DejaVuSansCondensed-Bold.ttf b/pages/DejaVuSansCondensed-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..16cc97bfeae1ef1cfbd76e2a064de6e3ad049f53 --- /dev/null +++ b/pages/DejaVuSansCondensed-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38098d0b8edd8430a0f53fb2831b5d36037563a998a620d3c87a4d7591766d20 +size 665028 diff --git a/pages/DejaVuSansCondensed-BoldOblique.ttf b/pages/DejaVuSansCondensed-BoldOblique.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bdd572a4c05dfa1fac5b508bad55b1bebc0d4d8b --- /dev/null +++ b/pages/DejaVuSansCondensed-BoldOblique.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c746f559a89415449e31b5e4e764b7896379723cf431a289902c2a660adf888b +size 580168 diff --git a/pages/DejaVuSansCondensed-Oblique.cw127.pkl b/pages/DejaVuSansCondensed-Oblique.cw127.pkl new file mode 100644 index 0000000000000000000000000000000000000000..8565480d62a5505f12362faf158f405b00e400e1 --- /dev/null +++ b/pages/DejaVuSansCondensed-Oblique.cw127.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce45b259575e9b7cb4ebbb6ce27d012ded2ec6ecd353c228e686dede98fb1c92 +size 510 diff --git a/pages/DejaVuSansCondensed-Oblique.pkl b/pages/DejaVuSansCondensed-Oblique.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0ea663f2b65f299e0afd55ec62c57c9af174d10d --- /dev/null +++ b/pages/DejaVuSansCondensed-Oblique.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1756c7afe56744bff2f73c6106d7ad1918fa3b415b5b66f4f4ed6d216b1c5c6f +size 136078 diff --git a/pages/DejaVuSansCondensed-Oblique.ttf b/pages/DejaVuSansCondensed-Oblique.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e85901337616a516f1e3c6c1b9dfeca89c8fb628 --- /dev/null +++ b/pages/DejaVuSansCondensed-Oblique.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a51e2dabf240996f7a2e501c23553246e7089be1b7507522f4ae18e2c6997612 +size 576004 diff --git a/pages/DejaVuSansCondensed.ttf b/pages/DejaVuSansCondensed.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b70bd9cbbebb44a7cf0f1e335b4e3619a6389eac --- /dev/null +++ b/pages/DejaVuSansCondensed.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9b9657f6dfe1d1a4b7cf0bd27f1183b6fc5edbb8435caa2d3a29539bbb89ca8 +size 544384 diff --git "a/pages/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" "b/pages/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..5b178c6a6ed40e77c73cebf950c178a3937c7e0f Binary files /dev/null and "b/pages/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" differ diff --git "a/pages/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" "b/pages/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..91310e5cf885724a3696b025cdebb8e7037cab30 Binary files /dev/null and "b/pages/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" differ diff --git a/pages/ErroreProportionMAximalStunden.ipynb b/pages/ErroreProportionMAximalStunden.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..492e2fc4dfe06e9d1f72ee00e807af84ec1f03d7 --- /dev/null +++ b/pages/ErroreProportionMAximalStunden.ipynb @@ -0,0 +1,2838 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Erklärung Gemeinden Jahr 2020 Tramin.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c74655a1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0Unnamed: 1Unnamed: 2Unnamed: 3Abrechnung für den Tagesmütter- / Tagesväterdienst - Jahr 2020Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9Unnamed: 10Unnamed: 11Unnamed: 12
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Trägerkörperschaft:NaNNaNSozialgenossenschaft Mit Bäuerinnen lernen-wac...NaNNaNNaNNaNNaNNaNNaNNaNNaN
3Wohnsitzgemeinde bzg. Gemeinde des ständigen A...NaNNaNTraminNaNNaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
7Fortlaufende\\nNummerNachname und Vorname des KindesGeburtsdatumSteuernummerTagesmutterWohnsitzgemeinde der TagesmutterDatum Vertragsbeginn (oder Datum Beginn der Be...Datum Vertragsende \\n(oder Datum Ende der Betr...Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt
81Chirone Riccardo2018-10-09 00:00:00CHRRCR18R09E986OSalvadori PaolaBozen2019-11-19 00:00:00NaN1308.7589.5NaN-3401058.25
92Frei Juri2018-05-29 00:00:00FREJRU18E29A952RPeer PetraKurtatsch2020-03-10 00:00:002020-05-05 00:00:00090NaN090
103Kajana Mia2018-08-03 00:00:00KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-18 00:00:00NaN559.524NaN-1.75581.75
113Kajana Mia2018-08-03 00:00:00KJNMIA18M43A952AAmbach MariaEppan2019-08-06 00:00:002020-05-04 00:00:0099.5144.75NaN66.25310.5
124Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NAmbach MariaEppan2020-08-17 00:00:002020-08-28 00:00:0071.50NaN071.5
134Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NHuber MelanieMargreid2020-11-25 00:00:002020-11-27 00:00:0026.50NaN026.5
144Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NPeer PetraKurtatsch2020-01-02 00:00:002020-05-06 00:00:00189.75270.5NaN332.5792.75
154Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NPeer PetraKurtatsch2020-07-20 00:00:00NaN80410.25NaN0814.25
165Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2020-07-20 00:00:002020-11-23 00:00:00231.520.75NaN0252.25
175Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2019-11-25 00:00:002020-05-06 00:00:00173.5279.5NaN364.5817.5
186Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-07-06 00:00:00NaN390.7520NaN0410.75
196Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PPeer PetraKurtatsch2020-02-03 00:00:002020-05-06 00:00:0055120NaN50225
206Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-02-07 00:00:002020-02-08 00:00:004.50NaN04.5
216Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-09-04 00:00:002020-09-04 00:00:0080NaN08
226Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-08-21 00:00:002020-08-21 00:00:0070NaN07
236Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PHuber MelanieMargreid2020-03-02 00:00:002020-03-04 00:00:00150NaN015
246Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-05-18 00:00:002020-06-18 00:00:0074.750NaN074.75
25NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
26NaNNaNNaNNaNNaNNaNNaNSumme4019.51069.250471.55560.25
27NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
28NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
29NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
30NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
31NaNDieser Jahresbericht entspricht dem Original, ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
32NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
33NaNUnterschrift des/der gesetzlichen Vertreters/i...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
34NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
35NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
36NaN* bei eventuellen Betreuungsverträgen, welche ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Trägerkörperschaft: \n", + "3 Wohnsitzgemeinde bzg. Gemeinde des ständigen A... \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Fortlaufende\\nNummer \n", + "8 1 \n", + "9 2 \n", + "10 3 \n", + "11 3 \n", + "12 4 \n", + "13 4 \n", + "14 4 \n", + "15 4 \n", + "16 5 \n", + "17 5 \n", + "18 6 \n", + "19 6 \n", + "20 6 \n", + "21 6 \n", + "22 6 \n", + "23 6 \n", + "24 6 \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 NaN NaN \n", + "5 NaN NaN \n", + "6 NaN NaN \n", + "7 Nachname und Vorname des Kindes Geburtsdatum \n", + "8 Chirone Riccardo 2018-10-09 00:00:00 \n", + "9 Frei Juri 2018-05-29 00:00:00 \n", + "10 Kajana Mia 2018-08-03 00:00:00 \n", + "11 Kajana Mia 2018-08-03 00:00:00 \n", + "12 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "13 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "14 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "15 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "16 Von Call Dylan 2019-02-19 00:00:00 \n", + "17 Von Call Dylan 2019-02-19 00:00:00 \n", + "18 Zelger Samuel 2018-05-08 00:00:00 \n", + "19 Zelger Samuel 2018-05-08 00:00:00 \n", + "20 Zelger Samuel 2018-05-08 00:00:00 \n", + "21 Zelger Samuel 2018-05-08 00:00:00 \n", + "22 Zelger Samuel 2018-05-08 00:00:00 \n", + "23 Zelger Samuel 2018-05-08 00:00:00 \n", + "24 Zelger Samuel 2018-05-08 00:00:00 \n", + "25 NaN NaN \n", + "26 NaN NaN \n", + "27 NaN NaN \n", + "28 NaN NaN \n", + "29 NaN NaN \n", + "30 NaN NaN \n", + "31 Dieser Jahresbericht entspricht dem Original, ... NaN \n", + "32 NaN NaN \n", + "33 Unterschrift des/der gesetzlichen Vertreters/i... NaN \n", + "34 NaN NaN \n", + "35 NaN NaN \n", + "36 * bei eventuellen Betreuungsverträgen, welche ... NaN \n", + "\n", + " Unnamed: 3 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Sozialgenossenschaft Mit Bäuerinnen lernen-wac... \n", + "3 Tramin \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Steuernummer \n", + "8 CHRRCR18R09E986O \n", + "9 FREJRU18E29A952R \n", + "10 KJNMIA18M43A952A \n", + "11 KJNMIA18M43A952A \n", + "12 TMGMRM19B41A952N \n", + "13 TMGMRM19B41A952N \n", + "14 TMGMRM19B41A952N \n", + "15 TMGMRM19B41A952N \n", + "16 VNCDLN19B19A952G \n", + "17 VNCDLN19B19A952G \n", + "18 ZLGSML18E08F132P \n", + "19 ZLGSML18E08F132P \n", + "20 ZLGSML18E08F132P \n", + "21 ZLGSML18E08F132P \n", + "22 ZLGSML18E08F132P \n", + "23 ZLGSML18E08F132P \n", + "24 ZLGSML18E08F132P \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Abrechnung für den Tagesmütter- / Tagesväterdienst - Jahr 2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Tagesmutter \n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 5 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Wohnsitzgemeinde der Tagesmutter \n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 6 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsbeginn (oder Datum Beginn der Be... \n", + "8 2019-11-19 00:00:00 \n", + "9 2020-03-10 00:00:00 \n", + "10 2020-05-18 00:00:00 \n", + "11 2019-08-06 00:00:00 \n", + "12 2020-08-17 00:00:00 \n", + "13 2020-11-25 00:00:00 \n", + "14 2020-01-02 00:00:00 \n", + "15 2020-07-20 00:00:00 \n", + "16 2020-07-20 00:00:00 \n", + "17 2019-11-25 00:00:00 \n", + "18 2020-07-06 00:00:00 \n", + "19 2020-02-03 00:00:00 \n", + "20 2020-02-07 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "23 2020-03-02 00:00:00 \n", + "24 2020-05-18 00:00:00 \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 7 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsende \\n(oder Datum Ende der Betr... \n", + "8 NaN \n", + "9 2020-05-05 00:00:00 \n", + "10 NaN \n", + "11 2020-05-04 00:00:00 \n", + "12 2020-08-28 00:00:00 \n", + "13 2020-11-27 00:00:00 \n", + "14 2020-05-06 00:00:00 \n", + "15 NaN \n", + "16 2020-11-23 00:00:00 \n", + "17 2020-05-06 00:00:00 \n", + "18 NaN \n", + "19 2020-05-06 00:00:00 \n", + "20 2020-02-08 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "23 2020-03-04 00:00:00 \n", + "24 2020-06-18 00:00:00 \n", + "25 NaN \n", + "26 Summe \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 8 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666... \n", + "8 1308.75 \n", + "9 0 \n", + "10 559.5 \n", + "11 99.5 \n", + "12 71.5 \n", + "13 26.5 \n", + "14 189.75 \n", + "15 804 \n", + "16 231.5 \n", + "17 173.5 \n", + "18 390.75 \n", + "19 55 \n", + "20 4.5 \n", + "21 8 \n", + "22 7 \n", + "23 15 \n", + "24 74.75 \n", + "25 NaN \n", + "26 4019.5 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 9 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 89.5 \n", + "9 90 \n", + "10 24 \n", + "11 144.75 \n", + "12 0 \n", + "13 0 \n", + "14 270.5 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.5 \n", + "18 20 \n", + "19 120 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 NaN \n", + "26 1069.25 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 10 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 NaN \n", + "9 NaN \n", + "10 NaN \n", + "11 NaN \n", + "12 NaN \n", + "13 NaN \n", + "14 NaN \n", + "15 NaN \n", + "16 NaN \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "20 NaN \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 0 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 11 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 -340 \n", + "9 0 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0 \n", + "13 0 \n", + "14 332.5 \n", + "15 0 \n", + "16 0 \n", + "17 364.5 \n", + "18 0 \n", + "19 50 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 NaN \n", + "26 471.5 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Unnamed: 12 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt \n", + "8 1058.25 \n", + "9 90 \n", + "10 581.75 \n", + "11 310.5 \n", + "12 71.5 \n", + "13 26.5 \n", + "14 792.75 \n", + "15 814.25 \n", + "16 252.25 \n", + "17 817.5 \n", + "18 410.75 \n", + "19 225 \n", + "20 4.5 \n", + "21 8 \n", + "22 7 \n", + "23 15 \n", + "24 74.75 \n", + "25 NaN \n", + "26 5560.25 \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Trägerkörperschaft: \n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale Sozialgenossenschaft Mit Bäuerinnen lernen-wac...\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) NaN\n", + "Ore totali rendicontate per il 2020 NaN\n", + "Name: 2, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f5ad0313", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = traeger[3].title()\n", + "gemeinde = df.iloc[3]\n", + "gemeinde = gemeinde[3]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "818d8c8d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Tramin'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "62d5bd44", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + " cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + " df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + " df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + " df = df[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "77d3ad34", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 11\n", + "Numero \\nprogressivo 3.0\n", + "Cognome e nome bambino Kajana Mia\n", + "Data di nascita 2018-08-03 00:00:00\n", + "Codice fiscale KJNMIA18M43A952A\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2019-08-06 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-05-04 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 99.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... 144.75\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 66.25\n", + "Ore totali rendicontate per il 2020 310.5\n", + " 12\n", + "Numero \\nprogressivo 4.0\n", + "Cognome e nome bambino Tomoiaga Ema Miriam\n", + "Data di nascita 2019-02-01 00:00:00\n", + "Codice fiscale TMGMRM19B41A952N\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-08-17 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-08-28 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 71.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... 0\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 71.5\n", + " 16\n", + "Numero \\nprogressivo 5.0\n", + "Cognome e nome bambino Von Call Dylan\n", + "Data di nascita 2019-02-19 00:00:00\n", + "Codice fiscale VNCDLN19B19A952G\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-07-20 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-11-23 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 231.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... 20.75\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 252.25\n", + " 17\n", + "Numero \\nprogressivo 5.0\n", + "Cognome e nome bambino Von Call Dylan\n", + "Data di nascita 2019-02-19 00:00:00\n", + "Codice fiscale VNCDLN19B19A952G\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2019-11-25 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-05-06 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 173.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... 279.5\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 364.5\n", + "Ore totali rendicontate per il 2020 817.5\n", + " 21\n", + "Numero \\nprogressivo 6.0\n", + "Cognome e nome bambino Zelger Samuel\n", + "Data di nascita 2018-05-08 00:00:00\n", + "Codice fiscale ZLGSML18E08F132P\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-09-04 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-09-04 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 8\n", + "Ore contrattualizzate non erogate\\nai sensi del... 0\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 8\n", + " 22\n", + "Numero \\nprogressivo 6.0\n", + "Cognome e nome bambino Zelger Samuel\n", + "Data di nascita 2018-05-08 00:00:00\n", + "Codice fiscale ZLGSML18E08F132P\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-08-21 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-08-21 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 7\n", + "Ore contrattualizzate non erogate\\nai sensi del... 0\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 7\n", + " 24\n", + "Numero \\nprogressivo 6.0\n", + "Cognome e nome bambino Zelger Samuel\n", + "Data di nascita 2018-05-08 00:00:00\n", + "Codice fiscale ZLGSML18E08F132P\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-05-18 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-06-18 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 74.75\n", + "Ore contrattualizzate non erogate\\nai sensi del... 0\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 74.75\n" + ] + } + ], + "source": [ + "for ind in df.index:\n", + " if df[\"Comune di residenza assistente domiciliare all'infanzia\"][ind].lower() in (\"eppan\"):\n", + " print(pd.DataFrame(df.loc[ind]))\n", + " pd.concat([ddff, pd.DataFrame(df.loc[ind])])" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "da922451", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
24
Numero \\nprogressivo6.0
Cognome e nome bambinoZelger Samuel
Data di nascita2018-05-08 00:00:00
Codice fiscaleZLGSML18E08F132P
Assistente domiciliare all'infanziaAmbach Maria
Comune di residenza assistente domiciliare all'infanziaEppan
Data inizio contratto (o data inizio assistenza se diversa)2020-05-18 00:00:00
Data fine contratto\\n(o data fine assistenza se diversa) *2020-06-18 00:00:00
Ore di assistenza \\n ai sensi della delibera\\nn. 666/201974.75
Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/20200
Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020NaN
Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)0
Ore totali rendicontate per il 202074.75
\n", + "
" + ], + "text/plain": [ + " 24\n", + "Numero \\nprogressivo 6.0\n", + "Cognome e nome bambino Zelger Samuel\n", + "Data di nascita 2018-05-08 00:00:00\n", + "Codice fiscale ZLGSML18E08F132P\n", + "Assistente domiciliare all'infanzia Ambach Maria\n", + "Comune di residenza assistente domiciliare all'... Eppan\n", + "Data inizio contratto (o data inizio assistenza... 2020-05-18 00:00:00\n", + "Data fine contratto\\n(o data fine assistenza se... 2020-06-18 00:00:00\n", + "Ore di assistenza \\n ai sensi della delibera\\nn... 74.75\n", + "Ore contrattualizzate non erogate\\nai sensi del... 0\n", + "Ore contrattualizzate non erogate\\nai sensi del... NaN\n", + "Ore contrattualizzate non erogate\\nnella fase 2... 0\n", + "Ore totali rendicontate per il 2020 74.75" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ddff" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "265efbee", + "metadata": {}, + "outputs": [], + "source": [ + "c = df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains('bozen|eppan')" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "90008ae8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 bozen\n", + "9 kurtatsch\n", + "10 kaltern\n", + "11 eppan\n", + "12 eppan\n", + "13 margreid\n", + "14 kurtatsch\n", + "15 kurtatsch\n", + "16 eppan\n", + "17 eppan\n", + "18 margreid\n", + "19 kurtatsch\n", + "20 margreid\n", + "21 eppan\n", + "22 eppan\n", + "23 margreid\n", + "24 eppan\n", + "Name: Comune di residenza assistente domiciliare all'infanzia, dtype: object" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "80ffa47b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
81.0Chirone Riccardo2018-10-09 00:00:00CHRRCR18R09E986OSalvadori PaolaBozen2019-11-19 00:00:00NaN1308.7589.5NaN-3401058.25
113.0Kajana Mia2018-08-03 00:00:00KJNMIA18M43A952AAmbach MariaEppan2019-08-06 00:00:002020-05-04 00:00:0099.5144.75NaN66.25310.5
124.0Tomoiaga Ema Miriam2019-02-01 00:00:00TMGMRM19B41A952NAmbach MariaEppan2020-08-17 00:00:002020-08-28 00:00:0071.50NaN071.5
165.0Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2020-07-20 00:00:002020-11-23 00:00:00231.520.75NaN0252.25
175.0Von Call Dylan2019-02-19 00:00:00VNCDLN19B19A952GAmbach MariaEppan2019-11-25 00:00:002020-05-06 00:00:00173.5279.5NaN364.5817.5
216.0Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-09-04 00:00:002020-09-04 00:00:0080NaN08
226.0Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-08-21 00:00:002020-08-21 00:00:0070NaN07
246.0Zelger Samuel2018-05-08 00:00:00ZLGSML18E08F132PAmbach MariaEppan2020-05-18 00:00:002020-06-18 00:00:0074.750NaN074.75
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 Chirone Riccardo 2018-10-09 00:00:00 \n", + "11 3.0 Kajana Mia 2018-08-03 00:00:00 \n", + "12 4.0 Tomoiaga Ema Miriam 2019-02-01 00:00:00 \n", + "16 5.0 Von Call Dylan 2019-02-19 00:00:00 \n", + "17 5.0 Von Call Dylan 2019-02-19 00:00:00 \n", + "21 6.0 Zelger Samuel 2018-05-08 00:00:00 \n", + "22 6.0 Zelger Samuel 2018-05-08 00:00:00 \n", + "24 6.0 Zelger Samuel 2018-05-08 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 CHRRCR18R09E986O Salvadori Paola \n", + "11 KJNMIA18M43A952A Ambach Maria \n", + "12 TMGMRM19B41A952N Ambach Maria \n", + "16 VNCDLN19B19A952G Ambach Maria \n", + "17 VNCDLN19B19A952G Ambach Maria \n", + "21 ZLGSML18E08F132P Ambach Maria \n", + "22 ZLGSML18E08F132P Ambach Maria \n", + "24 ZLGSML18E08F132P Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "11 Eppan \n", + "12 Eppan \n", + "16 Eppan \n", + "17 Eppan \n", + "21 Eppan \n", + "22 Eppan \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 00:00:00 \n", + "11 2019-08-06 00:00:00 \n", + "12 2020-08-17 00:00:00 \n", + "16 2020-07-20 00:00:00 \n", + "17 2019-11-25 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "24 2020-05-18 00:00:00 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 NaN \n", + "11 2020-05-04 00:00:00 \n", + "12 2020-08-28 00:00:00 \n", + "16 2020-11-23 00:00:00 \n", + "17 2020-05-06 00:00:00 \n", + "21 2020-09-04 00:00:00 \n", + "22 2020-08-21 00:00:00 \n", + "24 2020-06-18 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "11 99.5 \n", + "12 71.5 \n", + "16 231.5 \n", + "17 173.5 \n", + "21 8 \n", + "22 7 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.5 \n", + "11 144.75 \n", + "12 0 \n", + "16 20.75 \n", + "17 279.5 \n", + "21 0 \n", + "22 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 NaN \n", + "11 NaN \n", + "12 NaN \n", + "16 NaN \n", + "17 NaN \n", + "21 NaN \n", + "22 NaN \n", + "24 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340 \n", + "11 66.25 \n", + "12 0 \n", + "16 0 \n", + "17 364.5 \n", + "21 0 \n", + "22 0 \n", + "24 0 \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "8 1058.25 \n", + "11 310.5 \n", + "12 71.5 \n", + "16 252.25 \n", + "17 817.5 \n", + "21 8 \n", + "22 7 \n", + "24 74.75 " + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.loc[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2020" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "af6a6cf6", + "metadata": {}, + "outputs": [], + "source": [ + " condizioneerrore = ((1920 * (df[\"GiorniAssistenzaAnnoRiferimento\"])) / 366) < df[\n", + " \"Ore totali rendicontate per il 2020\"\n", + " ]\n", + " \n", + " condizioneerrore2 = ((1920 * (df.groupby(\"Codice fiscale\")[\"GiorniAssistenzaAnnoRiferimento\"].transform(\"sum\")) / 366)) < df.groupby(\"Codice fiscale\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\")" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "08e4a7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "VNCDLN19B19A952G\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n" + ] + } + ], + "source": [ + "for i in df[condizioneerrore][\"Codice fiscale\"]:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "29ed03dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-313661308.7589.500-340.001058.252020-01-012020-12-31
9Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-102020-05-05570.0090.0000.0090.002020-03-102020-05-05
10Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-182020-12-31228559.5024.000-1.75581.752020-05-182020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-0412599.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.0071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-27326.500.0000.0026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-06126189.75270.500332.50792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-31165804.0010.2500.00814.252020-07-202020-12-31
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-23127231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-06127173.50279.500364.50817.502020-01-012020-05-06
18Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-062020-12-31179390.7520.0000.00410.752020-07-062020-12-31
19Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-032020-05-069455.00120.00050.00225.002020-02-032020-05-06
20Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-072020-02-0824.500.0000.004.502020-02-072020-02-08
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-0418.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-2117.000.0000.007.002020-08-212020-08-21
23Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-022020-03-04315.000.0000.0015.002020-03-022020-03-04
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-183274.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "18 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "19 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "20 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "23 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "9 Tramin 2018-05-29 FREJRU18E29A952R \n", + "10 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "18 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "19 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "20 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "23 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "9 2020-03-10 \n", + "10 2020-05-18 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "18 2020-07-06 \n", + "19 2020-02-03 \n", + "20 2020-02-07 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-02 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "9 2020-05-05 \n", + "10 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "18 2020-12-31 \n", + "19 2020-05-06 \n", + "20 2020-02-08 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-04 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 366 \n", + "9 57 \n", + "10 228 \n", + "11 125 \n", + "12 12 \n", + "13 3 \n", + "14 126 \n", + "15 165 \n", + "16 127 \n", + "17 127 \n", + "18 179 \n", + "19 94 \n", + "20 2 \n", + "21 1 \n", + "22 1 \n", + "23 3 \n", + "24 32 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "9 0.00 \n", + "10 559.50 \n", + "11 99.50 \n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "16 231.50 \n", + "17 173.50 \n", + "18 390.75 \n", + "19 55.00 \n", + "20 4.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "23 15.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "9 90.00 \n", + "10 24.00 \n", + "11 144.75 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.50 \n", + "18 20.00 \n", + "19 120.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "9 0.00 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 332.50 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "18 0.00 \n", + "19 50.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "9 90.00 2020-03-10 2020-05-05 \n", + "10 581.75 2020-05-18 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "18 410.75 2020-07-06 2020-12-31 \n", + "19 225.00 2020-02-03 2020-05-06 \n", + "20 4.50 2020-02-07 2020-02-08 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "23 15.00 2020-03-02 2020-03-04 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9f22c6d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/GemeindenComuni.xlsx b/pages/GemeindenComuni.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..64b99d372256a8cd0cd1a096c01d6a77e3da4378 Binary files /dev/null and b/pages/GemeindenComuni.xlsx differ diff --git a/pages/GemeindenMitKodex.xlsx b/pages/GemeindenMitKodex.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..06b4e4ef5cfe6801904ea9e7c74ca91636e2000f Binary files /dev/null and b/pages/GemeindenMitKodex.xlsx differ diff --git a/pages/Gemischte KITA.docx b/pages/Gemischte KITA.docx new file mode 100644 index 0000000000000000000000000000000000000000..5ec269a0b34dbbdcaa8e464e174862ef8869259e Binary files /dev/null and b/pages/Gemischte KITA.docx differ diff --git a/pages/JahresBericht_Ahrntal_2021.xlsx b/pages/JahresBericht_Ahrntal_2021.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a668033382c93ec225dd0279c72021fe241e8a80 Binary files /dev/null and b/pages/JahresBericht_Ahrntal_2021.xlsx differ diff --git a/pages/JahresBericht_Ahrntal_2021_test.xlsx b/pages/JahresBericht_Ahrntal_2021_test.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5065087a1028350d161e259ecc168ab14fe57bed Binary files /dev/null and b/pages/JahresBericht_Ahrntal_2021_test.xlsx differ diff --git a/pages/Jahresbericht.xlsx b/pages/Jahresbericht.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..261240d5d1cc25922be98f19d0c91d994e9043f2 Binary files /dev/null and b/pages/Jahresbericht.xlsx differ diff --git a/pages/Jupyter/.ipynb_checkpoints/BambinoPiuComuni-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/BambinoPiuComuni-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..2ccc5d55023badecbb4a54f9973cc2daa2b82228 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/BambinoPiuComuni-checkpoint.ipynb @@ -0,0 +1,1662 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "983fbdd8", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "4f45a796", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Trägerkörperschaft:NaNNaNNaNSozialgenossenschaft Tagesmütter - Gen.NaNNaNNaNNaNNaNNaNNaNNaN
3Wohnsitzgemeinde bzg. Gemeinde des ständigen A...NaNNaNNaNEppan a.d. Weinstr.NaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
7Fortlaufende\\nNummerNachname und Vorname des KindesGeburtsdatumSteuernummerTagesmutterWohnsitzgemeinde der TagesmutterDatum Vertragsbeginn (oder Datum Beginn der Be...Datum Vertragsende \\n(oder Datum Ende der Betr...Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt
819ANZELONI AURELIA2017-05-07 00:00:00NZLRLA17E47A952ICAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2017-09-04 00:00:002020-06-19 00:00:00194.25381NaN314889.25
953BOCK FELIX2017-03-15 00:00:00BCKFLX17C15F132XVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2018-03-19 00:00:002020-08-28 00:00:00150288NaN159597
1063BRIGL HELENA2020-02-14 00:00:00BRGHLN20B54F132KRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2020-08-31 00:00:002023-02-10 00:00:00269.7525NaN0294.75
1182CHRISTOF DAVID2017-05-15 00:00:00CHRDVD17E15A952TCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-09-03 00:00:002020-06-16 00:00:00183.5326NaN269778.5
1283COCCA BENJAMIN2018-02-16 00:00:00CCCBJM18B16A952XRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-08-27 00:00:00565150NaN0.5715.5
1394DEJORI SIMON2019-03-02 00:00:00DJRSMN19C02A952TCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2019-09-02 00:00:002022-08-26 00:00:00777259.75NaN81044.75
14113FABI EMILIA2019-08-08 00:00:00FBAMLE19M48A952MWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2020-09-21 00:00:002022-09-02 00:00:002220NaN0222
15114FABI MARIE (TM)2016-12-20 00:00:00FBAMRA16T60F132XLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-04 00:00:002020-02-04 00:00:00630NaN063
16121FEDERA ALEX2017-07-28 00:00:00FDRLXA17L28A952TKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-21 00:00:002020-09-11 00:00:00412359NaN99.5870.5
17122FEDERA EMMA2020-02-11 00:00:00FDRMME20B51A952VKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2020-09-14 00:00:002021-12-31 00:00:0034726NaN0373
18135FINK ELLA2019-09-30 00:00:00FNKLLE19P70A952UKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2020-08-31 00:00:002022-09-02 00:00:00298.7527NaN0325.75
19145FRAU AARON2018-07-05 00:00:00FRARNA18L05A952ULANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-01 00:00:002021-06-25 00:00:00520150NaN89759
20187GRIESSMAIR SIMON2017-06-30 00:00:00GRSSMN17H30F132ECAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-02-08 00:00:002020-05-26 00:00:00208443NaNNaN651
21198HEISS JONAS2017-04-07 00:00:00HSSJNS17D07F132IPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2019-07-29 00:00:002020-06-09 00:00:00161240NaN152553
22211HOELBING FLIRI LOU2018-04-24 00:00:00HLBFRL18D24A952FVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-01-28 00:00:000216NaN101.75317.75
23212HOELBING FLIRI LOU2018-04-24 00:00:00HLBFRL18D24A952FLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-01-28 00:00:00409.75-10NaN0399.75
24217HOFER FIONA2018-03-05 00:00:00HFRFNI18C45A952UVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:000216NaN119335
25218HOFER FIONA2018-03-05 00:00:00HFRFNI18C45A952UWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:00315.259NaN0324.25
26223HOFER OLIVIA2018-03-05 00:00:00HFRLVO18C45A952WVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:000216NaN119335
27224HOFER OLIVIA2018-03-05 00:00:00HFRLVO18C45A952WWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:00315.259NaN0324.25
28240KAGER TONI2018-05-09 00:00:00KGRTNO18E09A952IRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-15 00:00:002021-08-27 00:00:00749.25219.5NaN30998.75
29250KNAPP MARTIN2019-08-09 00:00:00KNPMTN19M09C372WCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2020-06-08 00:00:002022-09-02 00:00:00476.525NaN-177.5324
30252KOESSLER JOHAN2019-01-02 00:00:00KSSJHN19A02A952NKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-04-01 00:00:002022-08-26 00:00:00513173NaN122808
31275LOBIS MANUEL2018-07-26 00:00:00LBSMNL18L26A952QLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-05-13 00:00:002021-09-03 00:00:00625170NaN-54741
32282MADEDDU DAVIS2017-01-08 00:00:00MDDDVS17A08A952NPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2018-01-08 00:00:002020-06-26 00:00:00150.75192NaN97439.75
33302MARSEILER NELLY2018-07-07 00:00:00MRSNLY18L47F132ERABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-19 00:00:002021-01-29 00:00:00627126.75NaN-9.25744.5
34305MASCALZONI MASSIMILIANO2017-04-10 00:00:00MSCMSM17D10A952UPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2018-02-19 00:00:002020-08-28 00:00:00203168NaN9380
35318MESSNER ELIN2017-07-27 00:00:00MSSLNE17L67F132ALANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-01-07 00:00:002020-09-04 00:00:00294165NaN14473
36319MESSNER MARTIN2018-07-29 00:00:00MSSMTN18L29B160ALANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-26 00:00:002021-09-03 00:00:00809250NaN1001159
37354OHNEWEIN RUDI2018-09-08 00:00:00HNWRDU18P08A952BKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-03-04 00:00:002021-08-27 00:00:00654.5252NaN9915.5
38363PEER PHILIPP RYAN2018-06-28 00:00:00PREPLP18H28A952KPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-26 00:00:002021-08-27 00:00:00552236NaN28816
39384PINTO FRANZISKA2019-01-29 00:00:00PNTFNZ19A69A952SKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-09-09 00:00:002021-08-27 00:00:00544167NaN-33.5677.5
40407RAIFER LISA2018-04-09 00:00:00RFRLSI18D49A952TRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2020-07-13 00:00:002021-08-27 00:00:00513.516NaN-143386.5
41507UNTERWEGER SIMON2018-03-30 00:00:00NTRSMN18C30F132WKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-04-01 00:00:002021-09-03 00:00:00397.25251NaN69.75718
42514VIAN SOFIA2019-05-24 00:00:00VNISFO19E64A952VPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2020-02-03 00:00:002022-08-26 00:00:00636.75360NaN541050.75
43515VIEHWEIDER PAUL2017-06-20 00:00:00VHWPLA17H20A952MRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2018-09-17 00:00:002020-08-28 00:00:00243135NaN15.5393.5
44524WALTER MARION2017-03-12 00:00:00WLTMRN17C52A952DKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2018-01-08 00:00:002020-08-28 00:00:00442.5348NaN73.25863.75
45551ZUBLASING EVA2017-08-16 00:00:00ZBLVEA17M56A952ECAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-01 00:00:002020-06-25 00:00:0084163NaN128375
46SummeNaNNaNNaNNaNNaNNaNNaN13926.567480176322437.5
47NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
48* bei eventuellen Betreuungsverträgen, welche ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
49NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
50NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
51NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
52Dieser Jahresbericht entspricht dem Original, ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
53NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
54Unterschrift des/der gesetzlichen Vertreters/i...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Trägerkörperschaft: \n", + "3 Wohnsitzgemeinde bzg. Gemeinde des ständigen A... \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Fortlaufende\\nNummer \n", + "8 19 \n", + "9 53 \n", + "10 63 \n", + "11 82 \n", + "12 83 \n", + "13 94 \n", + "14 113 \n", + "15 114 \n", + "16 121 \n", + "17 122 \n", + "18 135 \n", + "19 145 \n", + "20 187 \n", + "21 198 \n", + "22 211 \n", + "23 212 \n", + "24 217 \n", + "25 218 \n", + "26 223 \n", + "27 224 \n", + "28 240 \n", + "29 250 \n", + "30 252 \n", + "31 275 \n", + "32 282 \n", + "33 302 \n", + "34 305 \n", + "35 318 \n", + "36 319 \n", + "37 354 \n", + "38 363 \n", + "39 384 \n", + "40 407 \n", + "41 507 \n", + "42 514 \n", + "43 515 \n", + "44 524 \n", + "45 551 \n", + "46 Summe \n", + "47 NaN \n", + "48 * bei eventuellen Betreuungsverträgen, welche ... \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 Dieser Jahresbericht entspricht dem Original, ... \n", + "53 NaN \n", + "54 Unterschrift des/der gesetzlichen Vertreters/i... \n", + "\n", + " Cognome e nome bambino Data di nascita Codice fiscale \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 NaN NaN NaN \n", + "5 NaN NaN NaN \n", + "6 NaN NaN NaN \n", + "7 Nachname und Vorname des Kindes Geburtsdatum Steuernummer \n", + "8 ANZELONI AURELIA 2017-05-07 00:00:00 NZLRLA17E47A952I \n", + "9 BOCK FELIX 2017-03-15 00:00:00 BCKFLX17C15F132X \n", + "10 BRIGL HELENA 2020-02-14 00:00:00 BRGHLN20B54F132K \n", + "11 CHRISTOF DAVID 2017-05-15 00:00:00 CHRDVD17E15A952T \n", + "12 COCCA BENJAMIN 2018-02-16 00:00:00 CCCBJM18B16A952X \n", + "13 DEJORI SIMON 2019-03-02 00:00:00 DJRSMN19C02A952T \n", + "14 FABI EMILIA 2019-08-08 00:00:00 FBAMLE19M48A952M \n", + "15 FABI MARIE (TM) 2016-12-20 00:00:00 FBAMRA16T60F132X \n", + "16 FEDERA ALEX 2017-07-28 00:00:00 FDRLXA17L28A952T \n", + "17 FEDERA EMMA 2020-02-11 00:00:00 FDRMME20B51A952V \n", + "18 FINK ELLA 2019-09-30 00:00:00 FNKLLE19P70A952U \n", + "19 FRAU AARON 2018-07-05 00:00:00 FRARNA18L05A952U \n", + "20 GRIESSMAIR SIMON 2017-06-30 00:00:00 GRSSMN17H30F132E \n", + "21 HEISS JONAS 2017-04-07 00:00:00 HSSJNS17D07F132I \n", + "22 HOELBING FLIRI LOU 2018-04-24 00:00:00 HLBFRL18D24A952F \n", + "23 HOELBING FLIRI LOU 2018-04-24 00:00:00 HLBFRL18D24A952F \n", + "24 HOFER FIONA 2018-03-05 00:00:00 HFRFNI18C45A952U \n", + "25 HOFER FIONA 2018-03-05 00:00:00 HFRFNI18C45A952U \n", + "26 HOFER OLIVIA 2018-03-05 00:00:00 HFRLVO18C45A952W \n", + "27 HOFER OLIVIA 2018-03-05 00:00:00 HFRLVO18C45A952W \n", + "28 KAGER TONI 2018-05-09 00:00:00 KGRTNO18E09A952I \n", + "29 KNAPP MARTIN 2019-08-09 00:00:00 KNPMTN19M09C372W \n", + "30 KOESSLER JOHAN 2019-01-02 00:00:00 KSSJHN19A02A952N \n", + "31 LOBIS MANUEL 2018-07-26 00:00:00 LBSMNL18L26A952Q \n", + "32 MADEDDU DAVIS 2017-01-08 00:00:00 MDDDVS17A08A952N \n", + "33 MARSEILER NELLY 2018-07-07 00:00:00 MRSNLY18L47F132E \n", + "34 MASCALZONI MASSIMILIANO 2017-04-10 00:00:00 MSCMSM17D10A952U \n", + "35 MESSNER ELIN 2017-07-27 00:00:00 MSSLNE17L67F132A \n", + "36 MESSNER MARTIN 2018-07-29 00:00:00 MSSMTN18L29B160A \n", + "37 OHNEWEIN RUDI 2018-09-08 00:00:00 HNWRDU18P08A952B \n", + "38 PEER PHILIPP RYAN 2018-06-28 00:00:00 PREPLP18H28A952K \n", + "39 PINTO FRANZISKA 2019-01-29 00:00:00 PNTFNZ19A69A952S \n", + "40 RAIFER LISA 2018-04-09 00:00:00 RFRLSI18D49A952T \n", + "41 UNTERWEGER SIMON 2018-03-30 00:00:00 NTRSMN18C30F132W \n", + "42 VIAN SOFIA 2019-05-24 00:00:00 VNISFO19E64A952V \n", + "43 VIEHWEIDER PAUL 2017-06-20 00:00:00 VHWPLA17H20A952M \n", + "44 WALTER MARION 2017-03-12 00:00:00 WLTMRN17C52A952D \n", + "45 ZUBLASING EVA 2017-08-16 00:00:00 ZBLVEA17M56A952E \n", + "46 NaN NaN NaN \n", + "47 NaN NaN NaN \n", + "48 NaN NaN NaN \n", + "49 NaN NaN NaN \n", + "50 NaN NaN NaN \n", + "51 NaN NaN NaN \n", + "52 NaN NaN NaN \n", + "53 NaN NaN NaN \n", + "54 NaN NaN NaN \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Sozialgenossenschaft Tagesmütter - Gen. \n", + "3 Eppan a.d. Weinstr. \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Tagesmutter \n", + "8 CAPPELLO MARGARETH \n", + "9 VON DELLEMANN ANNA \n", + "10 RABANSER HELGA \n", + "11 CAPPELLO MARGARETH \n", + "12 RABANSER HELGA \n", + "13 CAPPELLO MARGARETH \n", + "14 WEGMANN NADYA \n", + "15 LANTHALER UTE \n", + "16 KIER CLAUDIA \n", + "17 KIER CLAUDIA \n", + "18 KIER CLAUDIA \n", + "19 LANTHALER UTE \n", + "20 CAPPELLO MARGARETH \n", + "21 PLATTNER HELENE \n", + "22 VON DELLEMANN ANNA \n", + "23 LANTHALER UTE \n", + "24 VON DELLEMANN ANNA \n", + "25 WEGMANN NADYA \n", + "26 VON DELLEMANN ANNA \n", + "27 WEGMANN NADYA \n", + "28 RABANSER HELGA \n", + "29 CAPPELLO MARGARETH \n", + "30 KIER CLAUDIA \n", + "31 LANTHALER UTE \n", + "32 PLATTNER HELENE \n", + "33 RABANSER HELGA \n", + "34 PLATTNER HELENE \n", + "35 LANTHALER UTE \n", + "36 LANTHALER UTE \n", + "37 KIER CLAUDIA \n", + "38 PLATTNER HELENE \n", + "39 KIER CLAUDIA \n", + "40 RABANSER HELGA \n", + "41 KIER CLAUDIA \n", + "42 PLATTNER HELENE \n", + "43 RABANSER HELGA \n", + "44 KIER CLAUDIA \n", + "45 CAPPELLO MARGARETH \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Wohnsitzgemeinde der Tagesmutter \n", + "8 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "9 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "10 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "11 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "12 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "13 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "14 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "15 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "16 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "17 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "18 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "19 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "20 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "21 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "22 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "23 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "24 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "25 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "26 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "27 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "28 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "29 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "30 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "31 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "32 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "33 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "34 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "35 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "36 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "37 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "38 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "39 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "40 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "41 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "42 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "43 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "44 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "45 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsbeginn (oder Datum Beginn der Be... \n", + "8 2017-09-04 00:00:00 \n", + "9 2018-03-19 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2018-09-03 00:00:00 \n", + "12 2019-02-18 00:00:00 \n", + "13 2019-09-02 00:00:00 \n", + "14 2020-09-21 00:00:00 \n", + "15 2019-02-04 00:00:00 \n", + "16 2019-10-21 00:00:00 \n", + "17 2020-09-14 00:00:00 \n", + "18 2020-08-31 00:00:00 \n", + "19 2018-10-01 00:00:00 \n", + "20 2018-02-08 00:00:00 \n", + "21 2019-07-29 00:00:00 \n", + "22 2019-02-18 00:00:00 \n", + "23 2019-02-18 00:00:00 \n", + "24 2019-10-07 00:00:00 \n", + "25 2019-10-07 00:00:00 \n", + "26 2019-10-07 00:00:00 \n", + "27 2019-10-07 00:00:00 \n", + "28 2018-10-15 00:00:00 \n", + "29 2020-06-08 00:00:00 \n", + "30 2019-04-01 00:00:00 \n", + "31 2019-05-13 00:00:00 \n", + "32 2018-01-08 00:00:00 \n", + "33 2019-08-19 00:00:00 \n", + "34 2018-02-19 00:00:00 \n", + "35 2019-01-07 00:00:00 \n", + "36 2019-08-26 00:00:00 \n", + "37 2019-03-04 00:00:00 \n", + "38 2019-08-26 00:00:00 \n", + "39 2019-09-09 00:00:00 \n", + "40 2020-07-13 00:00:00 \n", + "41 2019-04-01 00:00:00 \n", + "42 2020-02-03 00:00:00 \n", + "43 2018-09-17 00:00:00 \n", + "44 2018-01-08 00:00:00 \n", + "45 2018-10-01 00:00:00 \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsende \\n(oder Datum Ende der Betr... \n", + "8 2020-06-19 00:00:00 \n", + "9 2020-08-28 00:00:00 \n", + "10 2023-02-10 00:00:00 \n", + "11 2020-06-16 00:00:00 \n", + "12 2021-08-27 00:00:00 \n", + "13 2022-08-26 00:00:00 \n", + "14 2022-09-02 00:00:00 \n", + "15 2020-02-04 00:00:00 \n", + "16 2020-09-11 00:00:00 \n", + "17 2021-12-31 00:00:00 \n", + "18 2022-09-02 00:00:00 \n", + "19 2021-06-25 00:00:00 \n", + "20 2020-05-26 00:00:00 \n", + "21 2020-06-09 00:00:00 \n", + "22 2021-01-28 00:00:00 \n", + "23 2021-01-28 00:00:00 \n", + "24 2021-02-28 00:00:00 \n", + "25 2021-02-28 00:00:00 \n", + "26 2021-02-28 00:00:00 \n", + "27 2021-02-28 00:00:00 \n", + "28 2021-08-27 00:00:00 \n", + "29 2022-09-02 00:00:00 \n", + "30 2022-08-26 00:00:00 \n", + "31 2021-09-03 00:00:00 \n", + "32 2020-06-26 00:00:00 \n", + "33 2021-01-29 00:00:00 \n", + "34 2020-08-28 00:00:00 \n", + "35 2020-09-04 00:00:00 \n", + "36 2021-09-03 00:00:00 \n", + "37 2021-08-27 00:00:00 \n", + "38 2021-08-27 00:00:00 \n", + "39 2021-08-27 00:00:00 \n", + "40 2021-08-27 00:00:00 \n", + "41 2021-09-03 00:00:00 \n", + "42 2022-08-26 00:00:00 \n", + "43 2020-08-28 00:00:00 \n", + "44 2020-08-28 00:00:00 \n", + "45 2020-06-25 00:00:00 \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666... \n", + "8 194.25 \n", + "9 150 \n", + "10 269.75 \n", + "11 183.5 \n", + "12 565 \n", + "13 777 \n", + "14 222 \n", + "15 63 \n", + "16 412 \n", + "17 347 \n", + "18 298.75 \n", + "19 520 \n", + "20 208 \n", + "21 161 \n", + "22 0 \n", + "23 409.75 \n", + "24 0 \n", + "25 315.25 \n", + "26 0 \n", + "27 315.25 \n", + "28 749.25 \n", + "29 476.5 \n", + "30 513 \n", + "31 625 \n", + "32 150.75 \n", + "33 627 \n", + "34 203 \n", + "35 294 \n", + "36 809 \n", + "37 654.5 \n", + "38 552 \n", + "39 544 \n", + "40 513.5 \n", + "41 397.25 \n", + "42 636.75 \n", + "43 243 \n", + "44 442.5 \n", + "45 84 \n", + "46 13926.5 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 381 \n", + "9 288 \n", + "10 25 \n", + "11 326 \n", + "12 150 \n", + "13 259.75 \n", + "14 0 \n", + "15 0 \n", + "16 359 \n", + "17 26 \n", + "18 27 \n", + "19 150 \n", + "20 443 \n", + "21 240 \n", + "22 216 \n", + "23 -10 \n", + "24 216 \n", + "25 9 \n", + "26 216 \n", + "27 9 \n", + "28 219.5 \n", + "29 25 \n", + "30 173 \n", + "31 170 \n", + "32 192 \n", + "33 126.75 \n", + "34 168 \n", + "35 165 \n", + "36 250 \n", + "37 252 \n", + "38 236 \n", + "39 167 \n", + "40 16 \n", + "41 251 \n", + "42 360 \n", + "43 135 \n", + "44 348 \n", + "45 163 \n", + "46 6748 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 NaN \n", + "9 NaN \n", + "10 NaN \n", + "11 NaN \n", + "12 NaN \n", + "13 NaN \n", + "14 NaN \n", + "15 NaN \n", + "16 NaN \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "20 NaN \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "37 NaN \n", + "38 NaN \n", + "39 NaN \n", + "40 NaN \n", + "41 NaN \n", + "42 NaN \n", + "43 NaN \n", + "44 NaN \n", + "45 NaN \n", + "46 0 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 314 \n", + "9 159 \n", + "10 0 \n", + "11 269 \n", + "12 0.5 \n", + "13 8 \n", + "14 0 \n", + "15 0 \n", + "16 99.5 \n", + "17 0 \n", + "18 0 \n", + "19 89 \n", + "20 NaN \n", + "21 152 \n", + "22 101.75 \n", + "23 0 \n", + "24 119 \n", + "25 0 \n", + "26 119 \n", + "27 0 \n", + "28 30 \n", + "29 -177.5 \n", + "30 122 \n", + "31 -54 \n", + "32 97 \n", + "33 -9.25 \n", + "34 9 \n", + "35 14 \n", + "36 100 \n", + "37 9 \n", + "38 28 \n", + "39 -33.5 \n", + "40 -143 \n", + "41 69.75 \n", + "42 54 \n", + "43 15.5 \n", + "44 73.25 \n", + "45 128 \n", + "46 1763 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt \n", + "8 889.25 \n", + "9 597 \n", + "10 294.75 \n", + "11 778.5 \n", + "12 715.5 \n", + "13 1044.75 \n", + "14 222 \n", + "15 63 \n", + "16 870.5 \n", + "17 373 \n", + "18 325.75 \n", + "19 759 \n", + "20 651 \n", + "21 553 \n", + "22 317.75 \n", + "23 399.75 \n", + "24 335 \n", + "25 324.25 \n", + "26 335 \n", + "27 324.25 \n", + "28 998.75 \n", + "29 324 \n", + "30 808 \n", + "31 741 \n", + "32 439.75 \n", + "33 744.5 \n", + "34 380 \n", + "35 473 \n", + "36 1159 \n", + "37 915.5 \n", + "38 816 \n", + "39 677.5 \n", + "40 386.5 \n", + "41 718 \n", + "42 1050.75 \n", + "43 393.5 \n", + "44 863.75 \n", + "45 375 \n", + "46 22437.5 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faee8890", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true, + "vscode": { + "interpreter": { + "hash": "cf88d51bb359ca37aedeb3142437aa276b0f8132792620ce365bf5562ef1b43f" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/KindMehrfachnennung-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/KindMehrfachnennung-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b321adee64e286ee165d0af0169c8c8ce1e2ae4c --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/KindMehrfachnennung-checkpoint.ipynb @@ -0,0 +1,895 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 32, + "id": "27b85b04", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io\n", + "import copy" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "id": "5e8829fe", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Fehler Kind Mehrfachnennung.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "id": "d7bf08ae", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "476ed272", + "metadata": {}, + "outputs": [], + "source": [ + "df = {}\n", + "type(df)\n", + "df[\"sheet0\"] = None\n", + "df[\"sheet1\"] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "c8365ac8", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "d3905bd3", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "19222870", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce').isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce').isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "e09d0327", + "metadata": {}, + "outputs": [], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "c4549fa2", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "10dddc1a", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "c97c0d9e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine, delibera666, delibera543, delibera733, Entrate, errData]\n", + "Index: []" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "b9771f2b", + "metadata": {}, + "outputs": [], + "source": [ + "df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") " + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "cb1bb9e9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"sheet0\"] = df1\n", + "df[\"sheet1\"] = df2" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "fa87a9ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizioDataFine_xEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataFine_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-12-3150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleTerlano2019-09-30508NaNNaN1854.2<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x ComuneProvenienza_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataFine_y delibera666 delibera543 delibera733 Entrate \\\n", + "0 Avelengo 2020-12-31 500 100 10 750 \n", + "1 Terlano 2019-09-30 508 NaN NaN 1854.2 \n", + "\n", + " errData \n", + "0 \n", + "1 " + ] + }, + "execution_count": 109, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff = pd.merge(df1, df2, on=['Cognome','Nome','DataInizio'], how='inner')\n", + "mergedStuff" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "id": "80b9dc04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizio_xDataFineEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataInizio_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome utente_x \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst comunale \n", + "\n", + " ComuneProvenienza_x DataInizio_x DataFine \\\n", + "0 Andriano 2020-01-01 2020-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataInizio_y delibera666 delibera543 delibera733 \\\n", + "0 Avelengo 2020-01-01 500 100 10 \n", + "\n", + " Entrate errData \n", + "0 750 " + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff2 = pd.merge(df1, df2, on=['Cognome','Nome','DataFine'], how='inner')\n", + "mergedStuff2" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "id": "5c270e79", + "metadata": {}, + "outputs": [], + "source": [ + "m = pd.merge(mergedStuff, mergedStuff2, on=['Cognome','Nome'], how='outer')" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "id": "d8b57ba9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_x_xMicrostruttura_x_xCognomeNomeutente_x_xComuneProvenienza_x_xDataInizioDataFine_xEnte_y_xMicrostruttura_y_x...Ente_y_yMicrostruttura_y_yutente_y_yComuneProvenienza_y_yDataInizio_ydelibera666_ydelibera543_ydelibera733_yEntrate_yerrData_y
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine......Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine......NaNNaNNaNNaNNaTNaNNaNNaNNaN<NA>
\n", + "

2 rows × 34 columns

\n", + "
" + ], + "text/plain": [ + " Ente_x_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x_x ComuneProvenienza_x_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y_x \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y_x ... \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... ... \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... ... \n", + "\n", + " Ente_y_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 NaN \n", + "\n", + " Microstruttura_y_y utente_y_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 NaN NaN \n", + "\n", + " ComuneProvenienza_y_y DataInizio_y delibera666_y delibera543_y \\\n", + "0 Avelengo 2020-01-01 500 100 \n", + "1 NaN NaT NaN NaN \n", + "\n", + " delibera733_y Entrate_y errData_y \n", + "0 10 750 \n", + "1 NaN NaN \n", + "\n", + "[2 rows x 34 columns]" + ] + }, + "execution_count": 133, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "abdb5e65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizioDataFine_xEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataFine_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-12-3150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleTerlano2019-09-30508NaNNaN1854.2<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x ComuneProvenienza_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataFine_y delibera666 delibera543 delibera733 Entrate \\\n", + "0 Avelengo 2020-12-31 500 100 10 750 \n", + "1 Terlano 2019-09-30 508 NaN NaN 1854.2 \n", + "\n", + " errData \n", + "0 \n", + "1 " + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "id": "b8551529", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizio_xDataFineEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataInizio_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome utente_x \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst comunale \n", + "\n", + " ComuneProvenienza_x DataInizio_x DataFine \\\n", + "0 Andriano 2020-01-01 2020-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataInizio_y delibera666 delibera543 delibera733 \\\n", + "0 Avelengo 2020-01-01 500 100 10 \n", + "\n", + " Entrate errData \n", + "0 750 " + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbe6b90c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/Untitled6-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/Untitled6-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..9ee3ff34c00e2ccbe3c419b921498f844ad97384 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/Untitled6-checkpoint.ipynb @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "63d3f8dc", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cb57eafe", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"prospetto rendicontazione via combattenti 2019.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "879631c7", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.8/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "df = pd.read_excel(fn,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "9752d356", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Length mismatch: Expected axis has 8 elements, new values have 6 elements", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [54]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m df\u001b[38;5;241m.\u001b[39mdrop([\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnnamed: 6\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnnamed: 7\u001b[39m\u001b[38;5;124m\"\u001b[39m], axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m 2\u001b[0m df\u001b[38;5;241m.\u001b[39mdrop(labels\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;241m6\u001b[39m), axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m)\n\u001b[0;32m----> 3\u001b[0m df\u001b[38;5;241m.\u001b[39mcolumns \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 4\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCognome\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 5\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNome\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutente\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mComuneProvenienza\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataInizio\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 9\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataFine\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 10\u001b[0m ]\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:5500\u001b[0m, in \u001b[0;36mNDFrame.__setattr__\u001b[0;34m(self, name, value)\u001b[0m\n\u001b[1;32m 5498\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 5499\u001b[0m \u001b[38;5;28mobject\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__getattribute__\u001b[39m(\u001b[38;5;28mself\u001b[39m, name)\n\u001b[0;32m-> 5500\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mobject\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__setattr__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 5501\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mAttributeError\u001b[39;00m:\n\u001b[1;32m 5502\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/properties.pyx:70\u001b[0m, in \u001b[0;36mpandas._libs.properties.AxisProperty.__set__\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:766\u001b[0m, in \u001b[0;36mNDFrame._set_axis\u001b[0;34m(self, axis, labels)\u001b[0m\n\u001b[1;32m 764\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_set_axis\u001b[39m(\u001b[38;5;28mself\u001b[39m, axis: \u001b[38;5;28mint\u001b[39m, labels: Index) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 765\u001b[0m labels \u001b[38;5;241m=\u001b[39m ensure_index(labels)\n\u001b[0;32m--> 766\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_mgr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_axis\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 767\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_clear_item_cache()\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/internals/managers.py:216\u001b[0m, in \u001b[0;36mBaseBlockManager.set_axis\u001b[0;34m(self, axis, new_labels)\u001b[0m\n\u001b[1;32m 214\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mset_axis\u001b[39m(\u001b[38;5;28mself\u001b[39m, axis: \u001b[38;5;28mint\u001b[39m, new_labels: Index) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 215\u001b[0m \u001b[38;5;66;03m# Caller is responsible for ensuring we have an Index object.\u001b[39;00m\n\u001b[0;32m--> 216\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_set_axis\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnew_labels\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 217\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maxes[axis] \u001b[38;5;241m=\u001b[39m new_labels\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/internals/base.py:57\u001b[0m, in \u001b[0;36mDataManager._validate_set_axis\u001b[0;34m(self, axis, new_labels)\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[1;32m 56\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m new_len \u001b[38;5;241m!=\u001b[39m old_len:\n\u001b[0;32m---> 57\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 58\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mLength mismatch: Expected axis has \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mold_len\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m elements, new \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mvalues have \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mnew_len\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m elements\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 60\u001b[0m )\n", + "\u001b[0;31mValueError\u001b[0m: Length mismatch: Expected axis has 8 elements, new values have 6 elements" + ] + } + ], + "source": [ + "df.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df.drop(labels=range(0, 6), axis=0)\n", + "df.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "92af7737", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['elenco utenti precedenti', 'elenco utenti 2019', 'art kita', 'LK_Kita', 'LK_Comuni', 'LK_Gestori'])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "559a4d03", + "metadata": {}, + "outputs": [], + "source": [ + "df['elenco utenti precedenti']['Unnamed: 1'] = '11'" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "63c9766e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 11\n", + "1 11\n", + "2 11\n", + "3 11\n", + "4 11\n", + "5 11\n", + "6 11\n", + "7 11\n", + "8 11\n", + "9 11\n", + "10 11\n", + "11 11\n", + "12 11\n", + "13 11\n", + "Name: Unnamed: 1, dtype: object" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df['elenco utenti precedenti']['Unnamed: 1']" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "f965c06a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n" + ] + } + ], + "source": [ + "for a in (0,1):\n", + " print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "05b50f7c", + "metadata": {}, + "outputs": [], + "source": [ + "d = {}" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "b793976c", + "metadata": {}, + "outputs": [], + "source": [ + "d['sheet0'] = 'null'\n", + "d['sheet1'] = 'eins'" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "5b5c389c", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'df1' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [44]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m d[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msheet0\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mdf1\u001b[49m\n", + "\u001b[0;31mNameError\u001b[0m: name 'df1' is not defined" + ] + } + ], + "source": [ + "d['sheet0'] = df1" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "782907c6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "null\n", + "eins\n" + ] + } + ], + "source": [ + "for a in (0,1):\n", + " print(d['sheet'+str(a)])" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "725f4ff8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "sheet0\n", + "sheet1\n" + ] + } + ], + "source": [ + "for k in d:\n", + " print(k)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "c30c70b0", + "metadata": {}, + "outputs": [], + "source": [ + "COSTANTI ={}\n", + "costanti_2020 = {\"datainiziomin\": \"01.01.2017\", \"datainiziomax\": \"31.12.2020\", \"datafine\":\"31.12.2023\"}\n", + "COSTANTI = {\"2020\": costanti_2020}" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "d1b48a61", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'2020': {'datainiziomin': '01.01.2017',\n", + " 'datainiziomax': '31.12.2020',\n", + " 'datafine': '31.12.2023'}}" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "COSTANTI" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "5def7deb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'01.01.2017'" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "COSTANTI[\"2020\"][\"datainiziomin\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f32124", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/Untitled7-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/Untitled7-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/Untitled7-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/Untitled8-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/Untitled8-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/Untitled8-checkpoint.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/kitas-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/kitas-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..3af69643be09051593e1005aece126c8ec26bef3 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/kitas-checkpoint.ipynb @@ -0,0 +1,816 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5bff57df", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"prospetto rendicontazione via combattenti 2019.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "4634608a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.8/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "df1 = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "2f21a70c", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "a391f5de", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "id": "7bbd726c", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce').isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce').isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "id": "b421fd4a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...ABOUSIAMSaraaziendaleNaN2018-01-0231/09/2019NaNNaNNaNNaN<NA>
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRATTARELLIGianlucaaziendaleNaN2018-01-082019-08-31 00:00:00NaNNaNNaNNaN<NA>
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BISULTANOVKHADIJAcomunaleBozen / Bolzano2018-05-072020-08-31 00:00:001159.75NaNNaN1013.58<NA>
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...VECCHIATO GENTILEEDOARDOcomunaleBozen / Bolzano2018-09-102019-08-02 00:00:00962NaNNaN3511.32<NA>
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...ESPOSITO CAMILLANaNaziendaleNaN2018-09-242019-06-30 00:00:00NaNNaNNaNNaN<NA>
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...RAFFAGNINI LISANaNcomunaleBozen / Bolzano2018-10-012020-08-31 00:00:001399NaNNaN2622.53<NA>
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...OBKIRCHER CLARANaNaziendaleNaN2018-10-012020-08-31 00:00:00NaNNaNNaNNaN<NA>
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUGLIELMON MYANaNaziendaleNaN2019-01-142019-06-28 00:00:00NaNNaNNaNNaN<NA>
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...MINGIONE ANTONIONaNcomunaleBozen / Bolzano2019-03-112021-08-31 00:00:00885.25NaNNaN776.03<NA>
15Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...MINGIONE CAROLNaNcomunaleBozen / Bolzano2019-03-112021-08-31 00:00:00907.25NaNNaN791.38<NA>
16Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...RIZZO MARTINONaNcomunaleBozen / Bolzano2019-03-182019-07-31 00:00:00225.25NaNNaN822.16<NA>
17Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...RIZZO MARTINONaNaziendaleNaN2019-03-182019-07-31 00:00:00NaNNaNNaNNaN<NA>
18Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BOTTIGLIERI SALVATORE SAMUELENaNcomunaleBozen / Bolzano2019-05-202021-08-31 00:00:00385.4NaNNaN1047.09<NA>
19Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...MELON LEONARDONaNaziendaleNaN2019-05-272019-09-30 00:00:00NaNNaNNaNNaN<NA>
20Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BOERO VULCAN NAHUELNaNcomunaleBozen / Bolzano2019-07-152020-07-31 00:00:00498.75NaNNaN1820.44<NA>
21Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...CECCHETTO MARTINANaNaziendaleNaN2019-07-292021-08-31 00:00:00NaNNaNNaNNaN<NA>
22Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GNECCHI FABIONaNaziendaleNaN2019-09-092020-08-31 00:00:00NaNNaNNaNNaN<NA>
23Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PRONTERA SAMUELENaNaziendaleNaN2019-09-232022-08-31 00:00:00NaNNaNNaNNaN<NA>
24Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PICHLER ANNALENANaNaziendaleNaN2019-10-012021-08-31 00:00:00NaNNaNNaNNaN<NA>
25Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...LUCREZIA OSLERNaNaziendaleNaN2019-10-212021-08-31 00:00:00NaNNaNNaNNaN<NA>
26Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SECCHI ANDREANaNcomunaleBozen / Bolzano2019-11-042022-08-31 00:00:0093.5NaNNaN341.28<NA>
27Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SECCHI MASSIMILIANONaNcomunaleBozen / Bolzano2019-11-042022-08-31 00:00:0092.5NaNNaN83.25<NA>
28Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BALIVA MARTINNaNaziendaleNaN2019-11-042020-08-31 00:00:00NaNNaNNaNNaN<NA>
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "15 Cooperativa sociale Coccinella \n", + "16 Cooperativa sociale Coccinella \n", + "17 Cooperativa sociale Coccinella \n", + "18 Cooperativa sociale Coccinella \n", + "19 Cooperativa sociale Coccinella \n", + "20 Cooperativa sociale Coccinella \n", + "21 Cooperativa sociale Coccinella \n", + "22 Cooperativa sociale Coccinella \n", + "23 Cooperativa sociale Coccinella \n", + "24 Cooperativa sociale Coccinella \n", + "25 Cooperativa sociale Coccinella \n", + "26 Cooperativa sociale Coccinella \n", + "27 Cooperativa sociale Coccinella \n", + "28 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "15 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "16 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "17 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "18 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "19 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "20 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "21 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "22 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "23 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "24 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "25 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "26 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "27 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "28 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "\n", + " Cognome Nome utente ComuneProvenienza \\\n", + "6 ABOUSIAM Sara aziendale NaN \n", + "7 FRATTARELLI Gianluca aziendale NaN \n", + "8 BISULTANOV KHADIJA comunale Bozen / Bolzano \n", + "9 VECCHIATO GENTILE EDOARDO comunale Bozen / Bolzano \n", + "10 ESPOSITO CAMILLA NaN aziendale NaN \n", + "11 RAFFAGNINI LISA NaN comunale Bozen / Bolzano \n", + "12 OBKIRCHER CLARA NaN aziendale NaN \n", + "13 GUGLIELMON MYA NaN aziendale NaN \n", + "14 MINGIONE ANTONIO NaN comunale Bozen / Bolzano \n", + "15 MINGIONE CAROL NaN comunale Bozen / Bolzano \n", + "16 RIZZO MARTINO NaN comunale Bozen / Bolzano \n", + "17 RIZZO MARTINO NaN aziendale NaN \n", + "18 BOTTIGLIERI SALVATORE SAMUELE NaN comunale Bozen / Bolzano \n", + "19 MELON LEONARDO NaN aziendale NaN \n", + "20 BOERO VULCAN NAHUEL NaN comunale Bozen / Bolzano \n", + "21 CECCHETTO MARTINA NaN aziendale NaN \n", + "22 GNECCHI FABIO NaN aziendale NaN \n", + "23 PRONTERA SAMUELE NaN aziendale NaN \n", + "24 PICHLER ANNALENA NaN aziendale NaN \n", + "25 LUCREZIA OSLER NaN aziendale NaN \n", + "26 SECCHI ANDREA NaN comunale Bozen / Bolzano \n", + "27 SECCHI MASSIMILIANO NaN comunale Bozen / Bolzano \n", + "28 BALIVA MARTIN NaN aziendale NaN \n", + "\n", + " DataInizio DataFine delibera666 delibera543 delibera733 \\\n", + "6 2018-01-02 31/09/2019 NaN NaN NaN \n", + "7 2018-01-08 2019-08-31 00:00:00 NaN NaN NaN \n", + "8 2018-05-07 2020-08-31 00:00:00 1159.75 NaN NaN \n", + "9 2018-09-10 2019-08-02 00:00:00 962 NaN NaN \n", + "10 2018-09-24 2019-06-30 00:00:00 NaN NaN NaN \n", + "11 2018-10-01 2020-08-31 00:00:00 1399 NaN NaN \n", + "12 2018-10-01 2020-08-31 00:00:00 NaN NaN NaN \n", + "13 2019-01-14 2019-06-28 00:00:00 NaN NaN NaN \n", + "14 2019-03-11 2021-08-31 00:00:00 885.25 NaN NaN \n", + "15 2019-03-11 2021-08-31 00:00:00 907.25 NaN NaN \n", + "16 2019-03-18 2019-07-31 00:00:00 225.25 NaN NaN \n", + "17 2019-03-18 2019-07-31 00:00:00 NaN NaN NaN \n", + "18 2019-05-20 2021-08-31 00:00:00 385.4 NaN NaN \n", + "19 2019-05-27 2019-09-30 00:00:00 NaN NaN NaN \n", + "20 2019-07-15 2020-07-31 00:00:00 498.75 NaN NaN \n", + "21 2019-07-29 2021-08-31 00:00:00 NaN NaN NaN \n", + "22 2019-09-09 2020-08-31 00:00:00 NaN NaN NaN \n", + "23 2019-09-23 2022-08-31 00:00:00 NaN NaN NaN \n", + "24 2019-10-01 2021-08-31 00:00:00 NaN NaN NaN \n", + "25 2019-10-21 2021-08-31 00:00:00 NaN NaN NaN \n", + "26 2019-11-04 2022-08-31 00:00:00 93.5 NaN NaN \n", + "27 2019-11-04 2022-08-31 00:00:00 92.5 NaN NaN \n", + "28 2019-11-04 2020-08-31 00:00:00 NaN NaN NaN \n", + "\n", + " Entrate errData \n", + "6 NaN \n", + "7 NaN \n", + "8 1013.58 \n", + "9 3511.32 \n", + "10 NaN \n", + "11 2622.53 \n", + "12 NaN \n", + "13 NaN \n", + "14 776.03 \n", + "15 791.38 \n", + "16 822.16 \n", + "17 NaN \n", + "18 1047.09 \n", + "19 NaN \n", + "20 1820.44 \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 341.28 \n", + "27 83.25 \n", + "28 NaN " + ] + }, + "execution_count": 162, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "id": "b0c0b0d7", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 157, + "id": "d4610b79", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 159, + "id": "25246f11", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine, delibera666, delibera543, delibera733, Entrate, errData]\n", + "Index: []" + ] + }, + "execution_count": 159, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "2980f243", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "day is out of range for month", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/arrays/datetimes.py:2192\u001b[0m, in \u001b[0;36mobjects_to_datetime64ns\u001b[0;34m(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object, allow_mixed)\u001b[0m\n\u001b[1;32m 2191\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 2192\u001b[0m values, tz_parsed \u001b[38;5;241m=\u001b[39m \u001b[43mconversion\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdatetime_to_datetime64\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mravel\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mK\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2193\u001b[0m \u001b[38;5;66;03m# If tzaware, these values represent unix timestamps, so we\u001b[39;00m\n\u001b[1;32m 2194\u001b[0m \u001b[38;5;66;03m# return them as i8 to distinguish from wall times\u001b[39;00m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslibs/conversion.pyx:359\u001b[0m, in \u001b[0;36mpandas._libs.tslibs.conversion.datetime_to_datetime64\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: Unrecognized value type: ", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [93]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m df2[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataInizio\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m df2[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataInizio\u001b[39m\u001b[38;5;124m\"\u001b[39m]\u001b[38;5;241m.\u001b[39mastype(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdatetime64[ns]\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 2\u001b[0m df2[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDataFine\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mdf2\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mDataFine\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdatetime64[ns]\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:5815\u001b[0m, in \u001b[0;36mNDFrame.astype\u001b[0;34m(self, dtype, copy, errors)\u001b[0m\n\u001b[1;32m 5808\u001b[0m results \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m 5809\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39miloc[:, i]\u001b[38;5;241m.\u001b[39mastype(dtype, copy\u001b[38;5;241m=\u001b[39mcopy)\n\u001b[1;32m 5810\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns))\n\u001b[1;32m 5811\u001b[0m ]\n\u001b[1;32m 5813\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 5814\u001b[0m \u001b[38;5;66;03m# else, only a single dtype is given\u001b[39;00m\n\u001b[0;32m-> 5815\u001b[0m new_data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_mgr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 5816\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_constructor(new_data)\u001b[38;5;241m.\u001b[39m__finalize__(\u001b[38;5;28mself\u001b[39m, method\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mastype\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 5818\u001b[0m \u001b[38;5;66;03m# GH 33113: handle empty frame or series\u001b[39;00m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/internals/managers.py:418\u001b[0m, in \u001b[0;36mBaseBlockManager.astype\u001b[0;34m(self, dtype, copy, errors)\u001b[0m\n\u001b[1;32m 417\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mastype\u001b[39m(\u001b[38;5;28mself\u001b[39m: T, dtype, copy: \u001b[38;5;28mbool\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m, errors: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraise\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[0;32m--> 418\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapply\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mastype\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/internals/managers.py:327\u001b[0m, in \u001b[0;36mBaseBlockManager.apply\u001b[0;34m(self, f, align_keys, ignore_failures, **kwargs)\u001b[0m\n\u001b[1;32m 325\u001b[0m applied \u001b[38;5;241m=\u001b[39m b\u001b[38;5;241m.\u001b[39mapply(f, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 326\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 327\u001b[0m applied \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mb\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mf\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 328\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mTypeError\u001b[39;00m, \u001b[38;5;167;01mNotImplementedError\u001b[39;00m):\n\u001b[1;32m 329\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m ignore_failures:\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/internals/blocks.py:591\u001b[0m, in \u001b[0;36mBlock.astype\u001b[0;34m(self, dtype, copy, errors)\u001b[0m\n\u001b[1;32m 573\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 574\u001b[0m \u001b[38;5;124;03mCoerce to the new dtype.\u001b[39;00m\n\u001b[1;32m 575\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 587\u001b[0m \u001b[38;5;124;03mBlock\u001b[39;00m\n\u001b[1;32m 588\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 589\u001b[0m values \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvalues\n\u001b[0;32m--> 591\u001b[0m new_values \u001b[38;5;241m=\u001b[39m \u001b[43mastype_array_safe\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 593\u001b[0m new_values \u001b[38;5;241m=\u001b[39m maybe_coerce_values(new_values)\n\u001b[1;32m 594\u001b[0m newb \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmake_block(new_values)\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/dtypes/cast.py:1309\u001b[0m, in \u001b[0;36mastype_array_safe\u001b[0;34m(values, dtype, copy, errors)\u001b[0m\n\u001b[1;32m 1306\u001b[0m dtype \u001b[38;5;241m=\u001b[39m pandas_dtype(dtype)\n\u001b[1;32m 1308\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1309\u001b[0m new_values \u001b[38;5;241m=\u001b[39m \u001b[43mastype_array\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1310\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mValueError\u001b[39;00m, \u001b[38;5;167;01mTypeError\u001b[39;00m):\n\u001b[1;32m 1311\u001b[0m \u001b[38;5;66;03m# e.g. astype_nansafe can fail on object-dtype of strings\u001b[39;00m\n\u001b[1;32m 1312\u001b[0m \u001b[38;5;66;03m# trying to convert to float\u001b[39;00m\n\u001b[1;32m 1313\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m errors \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/dtypes/cast.py:1257\u001b[0m, in \u001b[0;36mastype_array\u001b[0;34m(values, dtype, copy)\u001b[0m\n\u001b[1;32m 1254\u001b[0m values \u001b[38;5;241m=\u001b[39m values\u001b[38;5;241m.\u001b[39mastype(dtype, copy\u001b[38;5;241m=\u001b[39mcopy)\n\u001b[1;32m 1256\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1257\u001b[0m values \u001b[38;5;241m=\u001b[39m \u001b[43mastype_nansafe\u001b[49m\u001b[43m(\u001b[49m\u001b[43mvalues\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcopy\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcopy\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1259\u001b[0m \u001b[38;5;66;03m# in pandas we don't store numpy str dtypes, so convert to object\u001b[39;00m\n\u001b[1;32m 1260\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(dtype, np\u001b[38;5;241m.\u001b[39mdtype) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(values\u001b[38;5;241m.\u001b[39mdtype\u001b[38;5;241m.\u001b[39mtype, \u001b[38;5;28mstr\u001b[39m):\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/dtypes/cast.py:1183\u001b[0m, in \u001b[0;36mastype_nansafe\u001b[0;34m(arr, dtype, copy, skipna)\u001b[0m\n\u001b[1;32m 1179\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m is_datetime64_dtype(dtype):\n\u001b[1;32m 1180\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m to_datetime\n\u001b[1;32m 1182\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m astype_nansafe(\n\u001b[0;32m-> 1183\u001b[0m \u001b[43mto_datetime\u001b[49m\u001b[43m(\u001b[49m\u001b[43marr\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mvalues,\n\u001b[1;32m 1184\u001b[0m dtype,\n\u001b[1;32m 1185\u001b[0m copy\u001b[38;5;241m=\u001b[39mcopy,\n\u001b[1;32m 1186\u001b[0m )\n\u001b[1;32m 1187\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m is_timedelta64_dtype(dtype):\n\u001b[1;32m 1188\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m to_timedelta\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/tools/datetimes.py:912\u001b[0m, in \u001b[0;36mto_datetime\u001b[0;34m(arg, errors, dayfirst, yearfirst, utc, format, exact, unit, infer_datetime_format, origin, cache)\u001b[0m\n\u001b[1;32m 910\u001b[0m result \u001b[38;5;241m=\u001b[39m _convert_and_box_cache(arg, cache_array)\n\u001b[1;32m 911\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 912\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mconvert_listlike\u001b[49m\u001b[43m(\u001b[49m\u001b[43marg\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 913\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 914\u001b[0m result \u001b[38;5;241m=\u001b[39m convert_listlike(np\u001b[38;5;241m.\u001b[39marray([arg]), \u001b[38;5;28mformat\u001b[39m)[\u001b[38;5;241m0\u001b[39m]\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/tools/datetimes.py:401\u001b[0m, in \u001b[0;36m_convert_listlike_datetimes\u001b[0;34m(arg, format, name, tz, unit, errors, infer_datetime_format, dayfirst, yearfirst, exact)\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28mformat\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mor\u001b[39;00m infer_datetime_format\n\u001b[1;32m 400\u001b[0m utc \u001b[38;5;241m=\u001b[39m tz \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mutc\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m--> 401\u001b[0m result, tz_parsed \u001b[38;5;241m=\u001b[39m \u001b[43mobjects_to_datetime64ns\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 402\u001b[0m \u001b[43m \u001b[49m\u001b[43marg\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 403\u001b[0m \u001b[43m \u001b[49m\u001b[43mdayfirst\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdayfirst\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 404\u001b[0m \u001b[43m \u001b[49m\u001b[43myearfirst\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43myearfirst\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 405\u001b[0m \u001b[43m \u001b[49m\u001b[43mutc\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mutc\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 406\u001b[0m \u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 407\u001b[0m \u001b[43m \u001b[49m\u001b[43mrequire_iso8601\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequire_iso8601\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 408\u001b[0m \u001b[43m \u001b[49m\u001b[43mallow_object\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 409\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 411\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m tz_parsed \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 412\u001b[0m \u001b[38;5;66;03m# We can take a shortcut since the datetime64 numpy array\u001b[39;00m\n\u001b[1;32m 413\u001b[0m \u001b[38;5;66;03m# is in UTC\u001b[39;00m\n\u001b[1;32m 414\u001b[0m dta \u001b[38;5;241m=\u001b[39m DatetimeArray(result, dtype\u001b[38;5;241m=\u001b[39mtz_to_dtype(tz_parsed))\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/arrays/datetimes.py:2198\u001b[0m, in \u001b[0;36mobjects_to_datetime64ns\u001b[0;34m(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object, allow_mixed)\u001b[0m\n\u001b[1;32m 2196\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m values\u001b[38;5;241m.\u001b[39mview(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mi8\u001b[39m\u001b[38;5;124m\"\u001b[39m), tz_parsed\n\u001b[1;32m 2197\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (\u001b[38;5;167;01mValueError\u001b[39;00m, \u001b[38;5;167;01mTypeError\u001b[39;00m):\n\u001b[0;32m-> 2198\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[1;32m 2200\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m tz_parsed \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 2201\u001b[0m \u001b[38;5;66;03m# We can take a shortcut since the datetime64 numpy array\u001b[39;00m\n\u001b[1;32m 2202\u001b[0m \u001b[38;5;66;03m# is in UTC\u001b[39;00m\n\u001b[1;32m 2203\u001b[0m \u001b[38;5;66;03m# Return i8 values to denote unix timestamps\u001b[39;00m\n\u001b[1;32m 2204\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\u001b[38;5;241m.\u001b[39mview(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mi8\u001b[39m\u001b[38;5;124m\"\u001b[39m), tz_parsed\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/arrays/datetimes.py:2180\u001b[0m, in \u001b[0;36mobjects_to_datetime64ns\u001b[0;34m(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object, allow_mixed)\u001b[0m\n\u001b[1;32m 2178\u001b[0m order: Literal[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mC\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m flags\u001b[38;5;241m.\u001b[39mf_contiguous \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mC\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 2179\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 2180\u001b[0m result, tz_parsed \u001b[38;5;241m=\u001b[39m \u001b[43mtslib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43marray_to_datetime\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2181\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mravel\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mK\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2182\u001b[0m \u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2183\u001b[0m \u001b[43m \u001b[49m\u001b[43mutc\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mutc\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2184\u001b[0m \u001b[43m \u001b[49m\u001b[43mdayfirst\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdayfirst\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2185\u001b[0m \u001b[43m \u001b[49m\u001b[43myearfirst\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43myearfirst\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2186\u001b[0m \u001b[43m \u001b[49m\u001b[43mrequire_iso8601\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequire_iso8601\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2187\u001b[0m \u001b[43m \u001b[49m\u001b[43mallow_mixed\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mallow_mixed\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 2188\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 2189\u001b[0m result \u001b[38;5;241m=\u001b[39m result\u001b[38;5;241m.\u001b[39mreshape(data\u001b[38;5;241m.\u001b[39mshape, order\u001b[38;5;241m=\u001b[39morder)\n\u001b[1;32m 2190\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslib.pyx:379\u001b[0m, in \u001b[0;36mpandas._libs.tslib.array_to_datetime\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslib.pyx:611\u001b[0m, in \u001b[0;36mpandas._libs.tslib.array_to_datetime\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslib.pyx:749\u001b[0m, in \u001b[0;36mpandas._libs.tslib._array_to_datetime_object\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslib.pyx:740\u001b[0m, in \u001b[0;36mpandas._libs.tslib._array_to_datetime_object\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslibs/parsing.pyx:244\u001b[0m, in \u001b[0;36mpandas._libs.tslibs.parsing.parse_datetime_string\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/tslibs/parsing.pyx:178\u001b[0m, in \u001b[0;36mpandas._libs.tslibs.parsing._parse_delimited_date\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mdatetime.pxd:120\u001b[0m, in \u001b[0;36mcpython.datetime.datetime_new\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: day is out of range for month" + ] + } + ], + "source": [ + "df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42e1dc85", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/kitas_2-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/kitas_2-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..8410f844a9895df15497ba1d648036ff33f2c1f7 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/kitas_2-checkpoint.ipynb @@ -0,0 +1,1504 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 405, + "id": "dd1858df", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 406, + "id": "92ce9948", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"prospetto rendicontazione via combattenti 2019.xlsx\"\n", + "fn2 = \"prospetto rendicontazione via combattenti 2019_bis.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 407, + "id": "07cb415e", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn2,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 408, + "id": "f889b62e", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n", + "df2 = df2.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df2.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 409, + "id": "9b2fa1f5", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "microstruttura = df.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df.iloc[2]\n", + "ente = ente[1]\n", + "df.insert(0, \"Microstruttura\", microstruttura)\n", + "df.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 410, + "id": "26c83573", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Cooperativa sociale Coccinella'" + ] + }, + "execution_count": 410, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ente" + ] + }, + { + "cell_type": "code", + "execution_count": 411, + "id": "bbf998b5", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "ente = df2.iloc[2]\n", + "ente = ente[2]\n", + "df2.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 412, + "id": "2ceac119", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
0Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
1Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...MicrostrutturaBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaN
2Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...Ente gestoreCooperativa Sociale BabycoopNaNNaNNaNNaN
3Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
4Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxx
5Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...cognomenomeNaNNaNNaNNaN
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "0 Cooperativa Sociale Babycoop \n", + "1 Cooperativa Sociale Babycoop \n", + "2 Cooperativa Sociale Babycoop \n", + "3 Cooperativa Sociale Babycoop \n", + "4 Cooperativa Sociale Babycoop \n", + "5 Cooperativa Sociale Babycoop \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "0 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... Microstruttura \n", + "2 Bolzano, Via Combattenti, 4, Coccinella (azien... Ente gestore \n", + "3 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "4 Bolzano, Via Combattenti, 4, Coccinella (azien... bambini \n", + "5 Bolzano, Via Combattenti, 4, Coccinella (azien... cognome \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome \\\n", + "0 NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "2 Cooperativa Sociale Babycoop \n", + "3 NaN \n", + "4 NaN \n", + "5 nome \n", + "6 NaN \n", + "7 Caio \n", + "\n", + " utente \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 utente aziendale o comunale \n", + "5 NaN \n", + "6 aziendale \n", + "7 comunale \n", + "\n", + " ComuneProvenienza \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + "5 NaN \n", + "6 NaN \n", + "7 Bozen / Bolzano \n", + "\n", + " DataInizio DataFine \n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + "5 NaN NaN \n", + "6 2017-11-20 00:00:00 2020-08-31 00:00:00 \n", + "7 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 412, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 413, + "id": "31362375", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 413, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "df = df.drop(labels=range(0, 6), axis=0)\n", + "df.columns\n", + "df2.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 414, + "id": "d1f89688", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 " + ] + }, + "execution_count": 414, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 415, + "id": "e54d5d6c", + "metadata": {}, + "outputs": [], + "source": [ + "dfout=None" + ] + }, + { + "cell_type": "code", + "execution_count": 416, + "id": "c9ef370d", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.DataFrame(columns=df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 417, + "id": "99753418", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine]\n", + "Index: []" + ] + }, + "execution_count": 417, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 418, + "id": "2d1e147a", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = df.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 419, + "id": "67797e3f", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.concat([dfout, df2])" + ] + }, + { + "cell_type": "code", + "execution_count": 420, + "id": "30b5262e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 420, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 421, + "id": "97691ba1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 421, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Cognome\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 442, + "id": "91c7d731", + "metadata": {}, + "outputs": [], + "source": [ + "c1 = dfout.groupby(\"Cognome\")[\"DataInizio\"].transform(\"nunique\") == 1\n", + "c2 = dfout.groupby(\"Cognome\")[\"Ente\"].transform(\"nunique\") > 1" + ] + }, + { + "cell_type": "code", + "execution_count": 443, + "id": "d5d89b41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome Nome utente \\\n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "\n", + " ComuneProvenienza DataInizio DataFine \n", + "14 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 \n", + "7 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 443, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout[c1 & c2]" + ] + }, + { + "cell_type": "code", + "execution_count": 433, + "id": "8b0ceda9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Borgo AliceCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Amato MicheleCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Gulino AlexaCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Furlan LeoCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10GUIBERTEAu GaelCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11FRASSANITO AlexCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12SCAFURO GIOVANNI GiovanniCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13NaNCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6NaNCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "6 Borgo Alice Cooperativa sociale Coccinella \n", + "7 Amato Michele Cooperativa sociale Coccinella \n", + "8 Gulino Alexa Cooperativa sociale Coccinella \n", + "9 Furlan Leo Cooperativa sociale Coccinella \n", + "10 GUIBERTEAu Gael Cooperativa sociale Coccinella \n", + "11 FRASSANITO Alex Cooperativa sociale Coccinella \n", + "12 SCAFURO GIOVANNI Giovanni Cooperativa sociale Coccinella \n", + "13 NaN Cooperativa sociale Coccinella \n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "6 NaN Cooperativa Sociale Babycoop \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 433, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 424, + "id": "c078a8d3", + "metadata": {}, + "outputs": [], + "source": [ + "dfout.insert(0, \"NomeCompleto\", dfout[\"Cognome\"] + \" \" + dfout[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 430, + "id": "a382688b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Borgo AliceCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Amato MicheleCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Gulino AlexaCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Furlan LeoCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10GUIBERTEAu GaelCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11FRASSANITO AlexCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12SCAFURO GIOVANNI GiovanniCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13NaNCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6NaNCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "6 Borgo Alice Cooperativa sociale Coccinella \n", + "7 Amato Michele Cooperativa sociale Coccinella \n", + "8 Gulino Alexa Cooperativa sociale Coccinella \n", + "9 Furlan Leo Cooperativa sociale Coccinella \n", + "10 GUIBERTEAu Gael Cooperativa sociale Coccinella \n", + "11 FRASSANITO Alex Cooperativa sociale Coccinella \n", + "12 SCAFURO GIOVANNI Giovanni Cooperativa sociale Coccinella \n", + "13 NaN Cooperativa sociale Coccinella \n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "6 NaN Cooperativa Sociale Babycoop \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 430, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e921c191", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/.ipynb_checkpoints/timeseries-checkpoint.ipynb b/pages/Jupyter/.ipynb_checkpoints/timeseries-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..ea03cd554fe5c6f20c2a7e67dfb2b3282e9cee72 --- /dev/null +++ b/pages/Jupyter/.ipynb_checkpoints/timeseries-checkpoint.ipynb @@ -0,0 +1,8530 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 14, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io\n", + "import copy" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5bff57df", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"1-prospetto rendicontazione microstrutture miste 2020.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "4634608a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.9/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n", + "/home/stfz/.local/lib/python3.9/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "\n", + "df1 = pd.read_excel(fn,0,parse_dates=['Unnamed: 4'])\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "86a8333d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Cognome object\n", + "Nome object\n", + "utente object\n", + "ComuneProvenienza object\n", + "DataInizio object\n", + "DataFine object\n", + "dtype: object" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "id": "c28713d0", + "metadata": {}, + "outputs": [], + "source": [ + "df = {}\n", + "type(df)\n", + "df[\"sheet0\"] = None\n", + "df[\"sheet1\"] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 237, + "id": "2f21a70c", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 238, + "id": "a34d988a", + "metadata": {}, + "outputs": [], + "source": [ + "#df2" + ] + }, + { + "cell_type": "code", + "execution_count": 239, + "id": "a391f5de", + "metadata": {}, + "outputs": [], + "source": [ + "#df1[\"DataInizio\"] = pd.to_datetime(df1['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df1[\"DataFine\"] = pd.to_datetime(df1['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataInizio\"] = pd.to_datetime(df2['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = pd.to_datetime(df2['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "#df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "id": "029df00d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 02.10.2017\n", + "7 02.10.2017\n", + "8 16.08.2018\n", + "9 27.08.2018\n", + "10 10.09.2018\n", + "11 17.09.2018\n", + "12 07.01.2019\n", + "13 07.03.2019\n", + "14 27.05.2019\n", + "15 05.07.2018\n", + "16 11.12.2017\n", + "17 23.08.2018\n", + "18 06.09.2018\n", + "19 26.11.2018\n", + "20 01.10.2018\n", + "21 03.02.2019\n", + "22 01.05.2019\n", + "23 02.04.2019\n", + "24 02.09.2019\n", + "Name: DataInizio, dtype: object" + ] + }, + "execution_count": 240, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1[\"DataInizio\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 241, + "id": "7bbd726c", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce',infer_datetime_format=True).isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce',infer_datetime_format=True).isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 242, + "id": "b421fd4a", + "metadata": {}, + "outputs": [], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 243, + "id": "36beb1b6", + "metadata": {}, + "outputs": [], + "source": [ + "#df1[\"DataInizio\"].astype(\"datetime64[ns]\").dt.year" + ] + }, + { + "cell_type": "code", + "execution_count": 244, + "id": "b0c0b0d7", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 245, + "id": "d4610b79", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 246, + "id": "25246f11", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.20202173425041009.05True
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020NaN418239714.6True
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.20205644404122058.6True
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021677288982471.05True
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021NaNNaNNaNNaNTrue
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020NaNNaNNaNNaNTrue
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020NaNNaNNaNNaNTrue
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021NaNNaNNaNNaNTrue
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022NaNNaNNaNNaNTrue
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.5241.52067.73True
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.52862067.73True
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023NaNNaNNaNNaNTrue
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021NaNNaNNaNNaNTrue
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine delibera666 \\\n", + "8 comunale Lana 16.08.2018 31.08.2020 217 \n", + "9 comunale Laives 27.08.2018 31.08.2020 NaN \n", + "11 comunale Merano 17.09.2018 31.08.2020 564 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 677 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 NaN \n", + "19 aziendale NaN 26.11.2018 31.08.2020 NaN \n", + "27 aziendale NaN 13.01.2020 31.12.2020 NaN \n", + "28 aziendale NaN 27.01.2020 31.06.2021 NaN \n", + "29 aziendale NaN 10.02.2020 31.06.2022 NaN \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 NaN \n", + "38 aziendale NaN 15.11.2020 31.08.2021 NaN \n", + "\n", + " delibera543 delibera733 Entrate errData \n", + "8 342 504 1009.05 True \n", + "9 418 239 714.6 True \n", + "11 440 412 2058.6 True \n", + "14 288 98 2471.05 True \n", + "17 NaN NaN NaN True \n", + "19 NaN NaN NaN True \n", + "27 NaN NaN NaN True \n", + "28 NaN NaN NaN True \n", + "29 NaN NaN NaN True \n", + "30 330.5 241.5 2067.73 True \n", + "31 330.5 286 2067.73 True \n", + "33 NaN NaN NaN True \n", + "38 NaN NaN NaN True " + ] + }, + "execution_count": 246, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 247, + "id": "0b48041a", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020NaN427.52312341.47<NA>
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020NaN427.52311295.83<NA>
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.20202173425041009.05True
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020NaN418239714.6True
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020535342197481.5<NA>
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.20205644404122058.6True
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021NaN3721973741.25<NA>
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021NaN3901203788.7<NA>
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021677288982471.05True
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020NaNNaNNaNNaN<NA>
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020NaNNaNNaNNaN<NA>
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021NaNNaNNaNNaNTrue
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020NaNNaNNaNNaN<NA>
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020NaNNaNNaNNaNTrue
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021NaNNaNNaNNaN<NA>
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021NaNNaNNaNNaN<NA>
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022NaNNaNNaNNaN<NA>
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020NaNNaNNaNNaN<NA>
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021NaNNaNNaNNaN<NA>
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021NaNNaNNaNNaN<NA>
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022NaNNaNNaNNaN<NA>
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020NaNNaNNaNNaNTrue
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021NaNNaNNaNNaNTrue
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022NaNNaNNaNNaNTrue
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.5241.52067.73True
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.52862067.73True
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.202294764703412.87<NA>
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023NaNNaNNaNNaNTrue
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022NaN40NaN1405.25<NA>
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021NaNNaNNaNNaN<NA>
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022NaNNaNNaNNaN<NA>
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021NaN48NaN1119.36<NA>
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021NaNNaNNaNNaNTrue
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine delibera666 \\\n", + "6 comunale Laives 02.10.2017 27.07.2020 NaN \n", + "7 comunale Laives 02.10.2017 27.07.2020 NaN \n", + "8 comunale Lana 16.08.2018 31.08.2020 217 \n", + "9 comunale Laives 27.08.2018 31.08.2020 NaN \n", + "10 comunale Vadena 10.09.2018 31.08.2020 535 \n", + "11 comunale Merano 17.09.2018 31.08.2020 564 \n", + "12 comunale Laives 07.01.2019 31.08.2021 NaN \n", + "13 comunale Laives 07.03.2019 31.08.2021 NaN \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 677 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 NaN \n", + "16 aziendale NaN 11.12.2017 31.08.2020 NaN \n", + "17 aziendale NaN 23.08.2018 31.08.2021 NaN \n", + "18 aziendale NaN 06.09.2018 30.09.2020 NaN \n", + "19 aziendale NaN 26.11.2018 31.08.2020 NaN \n", + "20 aziendale NaN 01.10.2018 31.08.2021 NaN \n", + "21 aziendale NaN 03.02.2019 08.02.2021 NaN \n", + "22 aziendale NaN 01.05.2019 31.08.2022 NaN \n", + "23 aziendale NaN 02.04.2019 31.08.2020 NaN \n", + "24 aziendale NaN 02.09.2019 31.08.2021 NaN \n", + "25 aziendale NaN 03.01.2020 31.08.2021 NaN \n", + "26 aziendale NaN 08.01.2020 31.08.2022 NaN \n", + "27 aziendale NaN 13.01.2020 31.12.2020 NaN \n", + "28 aziendale NaN 27.01.2020 31.06.2021 NaN \n", + "29 aziendale NaN 10.02.2020 31.06.2022 NaN \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 947 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 NaN \n", + "34 comunale Laives 01.09.2020 31.08.2022 NaN \n", + "35 aziendale NaN 07.09.2020 31.08.2021 NaN \n", + "36 aziendale NaN 08.09.2020 31.08.2022 NaN \n", + "37 comunale Laives 05.10.2020 31.12.2021 NaN \n", + "38 aziendale NaN 15.11.2020 31.08.2021 NaN \n", + "\n", + " delibera543 delibera733 Entrate errData \n", + "6 427.5 231 2341.47 \n", + "7 427.5 231 1295.83 \n", + "8 342 504 1009.05 True \n", + "9 418 239 714.6 True \n", + "10 342 197 481.5 \n", + "11 440 412 2058.6 True \n", + "12 372 197 3741.25 \n", + "13 390 120 3788.7 \n", + "14 288 98 2471.05 True \n", + "15 NaN NaN NaN \n", + "16 NaN NaN NaN \n", + "17 NaN NaN NaN True \n", + "18 NaN NaN NaN \n", + "19 NaN NaN NaN True \n", + "20 NaN NaN NaN \n", + "21 NaN NaN NaN \n", + "22 NaN NaN NaN \n", + "23 NaN NaN NaN \n", + "24 NaN NaN NaN \n", + "25 NaN NaN NaN \n", + "26 NaN NaN NaN \n", + "27 NaN NaN NaN True \n", + "28 NaN NaN NaN True \n", + "29 NaN NaN NaN True \n", + "30 330.5 241.5 2067.73 True \n", + "31 330.5 286 2067.73 True \n", + "32 64 70 3412.87 \n", + "33 NaN NaN NaN True \n", + "34 40 NaN 1405.25 \n", + "35 NaN NaN NaN \n", + "36 NaN NaN NaN \n", + "37 48 NaN 1119.36 \n", + "38 NaN NaN NaN True " + ] + }, + "execution_count": 247, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 248, + "id": "2980f243", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "#df2[\"DataInizio\"] = pd.to_datetime(df2['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = pd.to_datetime(df2['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") \n" + ] + }, + { + "cell_type": "code", + "execution_count": 249, + "id": "301e4317", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"].dt.strftime('%d.%m.%Y')" + ] + }, + { + "cell_type": "code", + "execution_count": 250, + "id": "d47d8671", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"] = df2[\"DataInizio\"].dt.strftime('%m.%d.%Y')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 251, + "id": "3882c1e6", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 252, + "id": "59461438", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"sheet0\"] = df1\n", + "df[\"sheet1\"] = df2" + ] + }, + { + "cell_type": "code", + "execution_count": 253, + "id": "4052946e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 " + ] + }, + "execution_count": 253, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"sheet0\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 254, + "id": "32908ff9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 254, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"sheet1\"][[\"Ente\", \"Microstruttura\", \"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 255, + "id": "b4daef8a", + "metadata": {}, + "outputs": [], + "source": [ + "frames = [df[\"sheet0\"], df[\"sheet1\"][[\"Ente\", \"Microstruttura\", \"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]]]\n", + "\n", + "result = pd.concat(frames)" + ] + }, + { + "cell_type": "code", + "execution_count": 256, + "id": "90bcfdcf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "22 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 256, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result.sort_values(by=['DataInizio'])" + ] + }, + { + "cell_type": "code", + "execution_count": 257, + "id": "46dfa0b4", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = result" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "id": "5748e823", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 200, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 258, + "id": "8bc9dc9b", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 258, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx = dfx.reset_index()\n", + "result = result.reset_index()\n", + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 228, + "id": "222e633d", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PILATO MARTIN\n", + "PILATO NOCOL\n", + "OIENI GIADA\n", + "SCAFAR VIKTORIA\n", + "TURANI NINA\n", + "MAXIMILIAN COCCO PAOLO\n", + "FERRARESE LEONARDO\n", + "BURAGLIO NICOL\n", + "MAYR DUFFEK VINCENT\n", + "TARGA MATILDE\n", + "COLLATUZZO TOMMASO\n", + "ISSAMM LAMRI\n", + "INNEREBNER MIA\n", + "BATTAN BRYAN LORENZO\n", + "NOMAN SOFIA\n", + "ER RQXQ RAZAN\n", + "BEQIRAJ KLARA\n", + "BEZZI GABRIEL\n", + "SCHMITTNER RAPHAEL\n", + "PILATO MARTIN\n", + "PILATO NICOL\n", + "OIENI GIADA\n", + "SCAFAR VIKTORIA\n", + "TURANI NINA\n", + "MAXIMILIAN COCCO PAOLO\n", + "FERRARESE LEONARDO\n", + "BURAGLIO NICOL\n", + "MAYR DUFFEK VINCENT\n", + "TARGA MATILDE\n", + "COLLATUZZO TOMMASO\n", + "ISSAMM LAMRI\n", + "INNEREBNER MIA\n", + "BATTAN BRYAN LORENZO\n", + "NOMAN SOFIA\n", + "ER RQXQ RAZAN\n", + "BEQIRAJ KLARA\n", + "BEZZI GABRIEL\n", + "SCHMITTNER RAPHAEL\n", + "TUTZER SOPHIE\n", + "VRENJO LOLA\n", + "BEQIRAJ EDUART\n", + "VRENJO DEA\n", + "CASTIONI MICHELE\n", + "PISCULA DAVID\n", + "PISCULA MICHAEL\n", + "OBKIRCHER REBECCA\n", + "SCHULLIAN FELIZIA\n", + "DI PASQUALE ESTHER\n", + "RISO ALICE\n", + "CHIFU SERENA\n", + "TOKA BREDLEY\n", + "TUTZER SOPHIE\n" + ] + } + ], + "source": [ + "for ind in dfx.index:\n", + " print(dfx['Cognome'][ind], dfx['Nome'][ind])" + ] + }, + { + "cell_type": "code", + "execution_count": 259, + "id": "fcf6e153", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = dfx.sort_values(by=['DataInizio'])\n", + "result = result.sort_values(by=['DataInizio'])" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "id": "3c35780e", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 230, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 262, + "id": "b9a3bee9", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['index', 'Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 262, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 265, + "id": "90794b99", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 265, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 276, + "id": "60337a79", + "metadata": {}, + "outputs": [], + "source": [ + "finddups = dfx[[\"Cognome\", \"Nome\", \"utente\", \"DataInizio\", \"DataFine\"]].duplicated()" + ] + }, + { + "cell_type": "code", + "execution_count": 279, + "id": "a9e24990", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = dfx[finddups]" + ] + }, + { + "cell_type": "code", + "execution_count": 280, + "id": "6afc40ca", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 280, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 272, + "id": "8e3006ec", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> contatore comunale = 0 e contatore aziendale = 1\n", + "\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> contatore comunale = 0 e contatore aziendale = 2\n", + "\n", + "bimbo comunale\t--> DI PASQUALE ESTHER \t--> contatore comunale = 1 e contatore aziendale = 2\n", + "\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> contatore comunale = 1 e contatore aziendale = 3\n", + "\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> contatore comunale = 1 e contatore aziendale = 4\n", + "\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> contatore comunale = 1 e contatore aziendale = 5\n", + "\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> contatore comunale = 1 e contatore aziendale = 6\n", + "\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> contatore comunale = 1 e contatore aziendale = 7\n", + "\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> contatore comunale = 1 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO MARTIN \t--> contatore comunale = 2 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO MARTIN \t--> contatore comunale = 3 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO NOCOL \t--> contatore comunale = 4 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO NICOL \t--> contatore comunale = 5 e contatore aziendale = 8\n", + "\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> contatore comunale = 5 e contatore aziendale = 9\n", + "\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> contatore comunale = 5 e contatore aziendale = 10\n", + "\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> contatore comunale = 5 e contatore aziendale = 11\n", + "\n", + "bimbo comunale\t--> OBKIRCHER REBECCA \t--> contatore comunale = 6 e contatore aziendale = 11\n", + "\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> contatore comunale = 6 e contatore aziendale = 12\n", + "\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> contatore comunale = 6 e contatore aziendale = 13\n", + "\n", + "bimbo comunale\t--> TOKA BREDLEY \t--> contatore comunale = 7 e contatore aziendale = 13\n", + "\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> contatore comunale = 7 e contatore aziendale = 14\n", + "\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> contatore comunale = 7 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> contatore comunale = 8 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> contatore comunale = 9 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> contatore comunale = 10 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> contatore comunale = 11 e contatore aziendale = 15\n", + "\n", + "bimbo aziendale\t--> RISO ALICE \t--> contatore comunale = 11 e contatore aziendale = 16\n", + "\n", + "bimbo aziendale\t--> VRENJO LOLA \t--> contatore comunale = 11 e contatore aziendale = 17\n", + "\n", + "CHIFU SERENA contatore aziendale = 18\n", + "Sottrazione --> contatore aziendale = 17\n", + "CHIFU SERENA contatore aziendale = 17\n", + "Sottrazione --> contatore aziendale = 16\n", + "bimbo aziendale\t--> CHIFU SERENA \t--> contatore comunale = 11 e contatore aziendale = 16\n", + "\n", + "bimbo aziendale\t--> CASTIONI MICHELE \t--> contatore comunale = 11 e contatore aziendale = 17\n", + "\n", + "bimbo comunale\t--> TURANI NINA \t--> contatore comunale = 12 e contatore aziendale = 17\n", + "\n", + "bimbo comunale\t--> TURANI NINA \t--> contatore comunale = 13 e contatore aziendale = 17\n", + "\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> contatore comunale = 13 e contatore aziendale = 18\n", + "\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> contatore comunale = 13 e contatore aziendale = 19\n", + "\n", + "bimbo aziendale\t--> BEQIRAJ EDUART \t--> contatore comunale = 13 e contatore aziendale = 20\n", + "\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> contatore comunale = 13 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> OIENI GIADA \t--> contatore comunale = 14 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> OIENI GIADA \t--> contatore comunale = 15 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> PISCULA DAVID \t--> contatore comunale = 16 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> PISCULA MICHAEL \t--> contatore comunale = 17 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> contatore comunale = 18 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> contatore comunale = 19 e contatore aziendale = 21\n", + "\n", + "bimbo aziendale\t--> SCHULLIAN FELIZIA \t--> contatore comunale = 19 e contatore aziendale = 22\n", + "\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> contatore comunale = 19 e contatore aziendale = 23\n", + "\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> contatore comunale = 19 e contatore aziendale = 24\n", + "\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> contatore comunale = 19 e contatore aziendale = 25\n", + "\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> contatore comunale = 19 e contatore aziendale = 26\n", + "\n", + "bimbo aziendale\t--> VRENJO DEA \t--> contatore comunale = 19 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> contatore comunale = 20 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> contatore comunale = 21 e contatore aziendale = 27\n", + "\n", + "SCAFAR VIKTORIA contatore comunale = 22\n", + "Sottrazione --> contatore comunale = 21\n", + "SCAFAR VIKTORIA contatore comunale = 21\n", + "Sottrazione --> contatore comunale = 20\n", + "SCAFAR VIKTORIA contatore comunale = 20\n", + "Sottrazione --> contatore comunale = 19\n", + "SCAFAR VIKTORIA contatore comunale = 19\n", + "Sottrazione --> contatore comunale = 18\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> contatore comunale = 18 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> contatore comunale = 19 e contatore aziendale = 27\n", + "\n", + "################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\n" + ] + } + ], + "source": [ + "DEBUGMODE = True\n", + "#result = dfx\n", + "cont_c = 0\n", + "cont_a = 0\n", + "datafineprecedenti_c = []\n", + "datafineprecedenti_a = []\n", + "\n", + "print(\n", + " \"################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\"\n", + ")\n", + "\n", + "# dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice\n", + "for ind in result.index:\n", + " # si tratta di utente comunale?\n", + " if result[\"utente\"][ind] == \"comunale\":\n", + " cont_c += 1 # incrementiamo il contatore\n", + " datafineprecedenti_c.append(\n", + " str(result[\"DataFine\"][ind])\n", + " ) # salviamo la data fine incontrata dureante iterazione\n", + " d_c = copy.copy(\n", + " datafineprecedenti_c\n", + " ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop\n", + " for (\n", + " a\n", + " ) in (\n", + " datafineprecedenti_c\n", + " ): # loopiamo tutte le data fine incontrate precedentemente\n", + " if (\n", + " str(result[\"DataInizio\"][ind]) > a\n", + " ): # se incontrata una data inizio superiore a una data fine già incontrata\n", + " if DEBUGMODE:\n", + " print(\n", + " result[\"Cognome\"][ind]\n", + " + \" \"\n", + " + result[\"Nome\"][ind]\n", + " + \" contatore comunale = \"\n", + " + str(cont_c)\n", + " )\n", + " cont_c -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\"Sottrazione --> contatore comunale = \" + str(cont_c))\n", + " d_c.remove(\n", + " a\n", + " ) # togliamo la data \"consumata\" dalla lista (copiata)\n", + " datafineprecedenti_c = copy.copy(\n", + " d_c\n", + " ) # deep copy della lista aggiornata (senza data fine \"consumate\")\n", + "\n", + " # si tratta di utente aziendale?\n", + " elif result[\"utente\"][ind] == \"aziendale\":\n", + " cont_a += 1 # incrementiamo il contatore\n", + " datafineprecedenti_a.append(\n", + " str(result[\"DataFine\"][ind])\n", + " ) # salviamo la data fine incontrata dureante iterazione\n", + " d_a = copy.copy(\n", + " datafineprecedenti_a\n", + " ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop\n", + " for (\n", + " a\n", + " ) in (\n", + " datafineprecedenti_a\n", + " ): # loopiamo tutte le data fine incontrate precedentemente\n", + " if (\n", + " str(result[\"DataInizio\"][ind]) > a\n", + " ): # se incontrata una data inizio superiore a una data fine già incontrata\n", + " if DEBUGMODE:\n", + " print(\n", + " result[\"Cognome\"][ind]\n", + " + \" \"\n", + " + result[\"Nome\"][ind]\n", + " + \" contatore aziendale = \"\n", + " + str(cont_a)\n", + " )\n", + " cont_a -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\"Sottrazione --> contatore aziendale = \" + str(cont_a))\n", + " d_a.remove(\n", + " a\n", + " ) # togliamo la data \"consumata\" dalla lista (copiata)\n", + " datafineprecedenti_a = copy.copy(\n", + " d_a\n", + " ) # deep copy della lista aggiornata (senza data fine \"consumate\")\n", + "\n", + " if DEBUGMODE:\n", + " print(\"bimbo \" + result[\"utente\"][ind] + \"\\t--> \" + result[\"Cognome\"][ind] + \" \" + result[\"Nome\"][ind] + \" \\t--> contatore comunale = \" + str(cont_c) + \" e contatore aziendale = \" + str(cont_a))\n", + " # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta\n", + " if (\n", + " (cont_c >= cont_a)\n", + " and result[\"utente\"][ind] == \"comunale\"\n", + " and result[\"DataInizio\"][ind]\n", + " >= pd.to_datetime(\"03.10.2017\", format=\"%d.%m.%Y\")\n", + " ):\n", + "\n", + " # st.write(\"trovato!!!!!!!\")\n", + " print(\n", + " f\"[*] Bimbo {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {result['delibera666'][ind]}\"\n", + " )\n", + " cont_c -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\n", + " \"tolto bimbo: contatore comunale = \"\n", + " + str(cont_c)\n", + " + \" e contatore aziendale = \"\n", + " + str(cont_a)\n", + " )\n", + " print()\n", + "print(\n", + " \"################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 231, + "id": "3b18d4b0", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> cont_c = 0 and cont_a = 1\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> cont_c = 0 and cont_a = 2\n", + "bimbo comunale\t--> DI PASQUALE ESTHER \t--> cont_c = 1 and cont_a = 2\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> cont_c = 1 and cont_a = 3\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> cont_c = 1 and cont_a = 4\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> cont_c = 1 and cont_a = 5\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> cont_c = 1 and cont_a = 6\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> cont_c = 1 and cont_a = 7\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> cont_c = 1 and cont_a = 8\n", + "bimbo comunale\t--> PILATO MARTIN \t--> cont_c = 2 and cont_a = 8\n", + "bimbo comunale\t--> PILATO MARTIN \t--> cont_c = 3 and cont_a = 8\n", + "bimbo comunale\t--> PILATO NOCOL \t--> cont_c = 4 and cont_a = 8\n", + "bimbo comunale\t--> PILATO NICOL \t--> cont_c = 5 and cont_a = 8\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> cont_c = 5 and cont_a = 9\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> cont_c = 5 and cont_a = 10\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> cont_c = 5 and cont_a = 11\n", + "bimbo comunale\t--> OBKIRCHER REBECCA \t--> cont_c = 6 and cont_a = 11\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> cont_c = 6 and cont_a = 12\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> cont_c = 6 and cont_a = 13\n", + "bimbo comunale\t--> TOKA BREDLEY \t--> cont_c = 7 and cont_a = 13\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> cont_c = 7 and cont_a = 14\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> cont_c = 7 and cont_a = 15\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> cont_c = 8 and cont_a = 15\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> cont_c = 9 and cont_a = 15\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> cont_c = 10 and cont_a = 15\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> cont_c = 11 and cont_a = 15\n", + "bimbo aziendale\t--> RISO ALICE \t--> cont_c = 11 and cont_a = 16\n", + "bimbo aziendale\t--> VRENJO LOLA \t--> cont_c = 11 and cont_a = 17\n", + "\n", + "CHIFU SERENA cont_a = 18\n", + "Sottrazione --> cont_a = 17\n", + "\n", + "\n", + "CHIFU SERENA cont_a = 17\n", + "Sottrazione --> cont_a = 16\n", + "\n", + "bimbo aziendale\t--> CHIFU SERENA \t--> cont_c = 11 and cont_a = 16\n", + "bimbo aziendale\t--> CASTIONI MICHELE \t--> cont_c = 11 and cont_a = 17\n", + "bimbo comunale\t--> TURANI NINA \t--> cont_c = 12 and cont_a = 17\n", + "bimbo comunale\t--> TURANI NINA \t--> cont_c = 13 and cont_a = 17\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> cont_c = 13 and cont_a = 18\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> cont_c = 13 and cont_a = 19\n", + "bimbo aziendale\t--> BEQIRAJ EDUART \t--> cont_c = 13 and cont_a = 20\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> cont_c = 13 and cont_a = 21\n", + "bimbo comunale\t--> OIENI GIADA \t--> cont_c = 14 and cont_a = 21\n", + "bimbo comunale\t--> OIENI GIADA \t--> cont_c = 15 and cont_a = 21\n", + "bimbo comunale\t--> PISCULA DAVID \t--> cont_c = 16 and cont_a = 21\n", + "bimbo comunale\t--> PISCULA MICHAEL \t--> cont_c = 17 and cont_a = 21\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> cont_c = 18 and cont_a = 21\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> cont_c = 19 and cont_a = 21\n", + "bimbo aziendale\t--> SCHULLIAN FELIZIA \t--> cont_c = 19 and cont_a = 22\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> cont_c = 19 and cont_a = 23\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> cont_c = 19 and cont_a = 24\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> cont_c = 19 and cont_a = 25\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> cont_c = 19 and cont_a = 26\n", + "bimbo aziendale\t--> VRENJO DEA \t--> cont_c = 19 and cont_a = 27\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> cont_c = 20 and cont_a = 27\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> cont_c = 21 and cont_a = 27\n", + "\n", + "SCAFAR VIKTORIA cont_c = 22\n", + "Sottrazione --> cont_c = 21\n", + "\n", + "SCAFAR VIKTORIA cont_c = 21\n", + "Sottrazione --> cont_c = 20\n", + "\n", + "SCAFAR VIKTORIA cont_c = 20\n", + "Sottrazione --> cont_c = 19\n", + "\n", + "SCAFAR VIKTORIA cont_c = 19\n", + "Sottrazione --> cont_c = 18\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> cont_c = 18 and cont_a = 27\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> cont_c = 19 and cont_a = 27\n", + "\n", + "################### END OF ITERATION ###################\n" + ] + } + ], + "source": [ + "cont_c = 0\n", + "cont_a = 0\n", + "datafineprecedenti_c = []\n", + "datafineprecedenti_a = []\n", + "\n", + "for ind in dfx.index:\n", + " \n", + " if dfx['utente'][ind] == \"comunale\":\n", + " cont_c += 1\n", + " datafineprecedenti_c.append(str(dfx[\"DataFine\"][ind]))\n", + " d_c = copy.copy(datafineprecedenti_c)\n", + " for a in datafineprecedenti_c:\n", + " if str(dfx[\"DataInizio\"][ind]) > a:\n", + " print()\n", + " print(dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] +\" cont_c = \" + str(cont_c))\n", + " cont_c -= 1\n", + " print(\"Sottrazione --> cont_c = \" + str(cont_c))\n", + " d_c.remove(a)\n", + " datafineprecedenti_c = copy.copy(d_c)\n", + " \n", + " \n", + " elif dfx['utente'][ind] == \"aziendale\":\n", + " cont_a += 1\n", + " datafineprecedenti_a.append(str(dfx[\"DataFine\"][ind]))\n", + " d_a = copy.copy(datafineprecedenti_a)\n", + " for a in datafineprecedenti_a:\n", + " if str(dfx[\"DataInizio\"][ind]) > a:\n", + " print()\n", + " print(dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] +\" cont_a = \" + str(cont_a))\n", + " cont_a -= 1\n", + " print(\"Sottrazione --> cont_a = \" + str(cont_a))\n", + " d_a.remove(a)\n", + " print()\n", + " datafineprecedenti_a = copy.copy(d_a)\n", + " \n", + " \n", + " print(\"bimbo \" + dfx[\"utente\"][ind] + \"\\t--> \" + dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] + \" \\t--> cont_c = \" + str(cont_c) + \" and cont_a = \" + str(cont_a)) \n", + " \n", + " if (cont_c >= cont_a) and dfx[\"utente\"][ind] == \"comunale\" and dfx['DataInizio'][ind] >= pd.to_datetime(\"3.10.2017\", format=\"%d.%m.%Y\"):\n", + " print()\n", + " print(\"Bimbo \" + dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] + \" \\tin eccesso COMUNALE, in data \" + str(dfx[\"DataInizio\"].dt.strftime('%d/%m/%Y')[ind]))\n", + " cont_c -= 1\n", + " print(\"tolto bimbo: cont_c = \" + str(cont_c) + \" and cont_a = \" + str(cont_a)) \n", + " print()\n", + "print() \n", + "print(\"################### END OF ITERATION ###################\")\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 209, + "id": "4486acde", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
level_0indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
03522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
11622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
24734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
33320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
41420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
51723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
63623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
71824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
83724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
12207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
9196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
1006Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
133825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
141521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
153421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
164532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
172815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
18915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
195037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
203118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
211218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
222512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
23612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
25713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
242613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
264835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
273926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
284936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
294229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
302310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
31410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
322916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
331016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
344027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
355138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
37218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
3628Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
394431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
384330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
402411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
41511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
424633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
431117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
443017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
453219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
461319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
474128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
482714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
49814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
50229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
5139Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " level_0 index Ente \\\n", + "0 35 22 Xenia Cooperativa Sociale Onlus \n", + "1 16 22 Xenia Cooperativa Sociale Onlus \n", + "2 47 34 Xenia Cooperativa Sociale Onlus \n", + "3 33 20 Xenia Cooperativa Sociale Onlus \n", + "4 14 20 Xenia Cooperativa Sociale Onlus \n", + "5 17 23 Xenia Cooperativa Sociale Onlus \n", + "6 36 23 Xenia Cooperativa Sociale Onlus \n", + "7 18 24 Xenia Cooperativa Sociale Onlus \n", + "8 37 24 Xenia Cooperativa Sociale Onlus \n", + "12 20 7 Xenia Cooperativa Sociale Onlus \n", + "11 1 7 Xenia Cooperativa Sociale Onlus \n", + "9 19 6 Xenia Cooperativa Sociale Onlus \n", + "10 0 6 Xenia Cooperativa Sociale Onlus \n", + "13 38 25 Xenia Cooperativa Sociale Onlus \n", + "14 15 21 Xenia Cooperativa Sociale Onlus \n", + "15 34 21 Xenia Cooperativa Sociale Onlus \n", + "16 45 32 Xenia Cooperativa Sociale Onlus \n", + "17 28 15 Xenia Cooperativa Sociale Onlus \n", + "18 9 15 Xenia Cooperativa Sociale Onlus \n", + "19 50 37 Xenia Cooperativa Sociale Onlus \n", + "20 31 18 Xenia Cooperativa Sociale Onlus \n", + "21 12 18 Xenia Cooperativa Sociale Onlus \n", + "22 25 12 Xenia Cooperativa Sociale Onlus \n", + "23 6 12 Xenia Cooperativa Sociale Onlus \n", + "25 7 13 Xenia Cooperativa Sociale Onlus \n", + "24 26 13 Xenia Cooperativa Sociale Onlus \n", + "26 48 35 Xenia Cooperativa Sociale Onlus \n", + "27 39 26 Xenia Cooperativa Sociale Onlus \n", + "28 49 36 Xenia Cooperativa Sociale Onlus \n", + "29 42 29 Xenia Cooperativa Sociale Onlus \n", + "30 23 10 Xenia Cooperativa Sociale Onlus \n", + "31 4 10 Xenia Cooperativa Sociale Onlus \n", + "32 29 16 Xenia Cooperativa Sociale Onlus \n", + "33 10 16 Xenia Cooperativa Sociale Onlus \n", + "34 40 27 Xenia Cooperativa Sociale Onlus \n", + "35 51 38 Xenia Cooperativa Sociale Onlus \n", + "37 21 8 Xenia Cooperativa Sociale Onlus \n", + "36 2 8 Xenia Cooperativa Sociale Onlus \n", + "39 44 31 Xenia Cooperativa Sociale Onlus \n", + "38 43 30 Xenia Cooperativa Sociale Onlus \n", + "40 24 11 Xenia Cooperativa Sociale Onlus \n", + "41 5 11 Xenia Cooperativa Sociale Onlus \n", + "42 46 33 Xenia Cooperativa Sociale Onlus \n", + "43 11 17 Xenia Cooperativa Sociale Onlus \n", + "44 30 17 Xenia Cooperativa Sociale Onlus \n", + "45 32 19 Xenia Cooperativa Sociale Onlus \n", + "46 13 19 Xenia Cooperativa Sociale Onlus \n", + "47 41 28 Xenia Cooperativa Sociale Onlus \n", + "48 27 14 Xenia Cooperativa Sociale Onlus \n", + "49 8 14 Xenia Cooperativa Sociale Onlus \n", + "50 22 9 Xenia Cooperativa Sociale Onlus \n", + "51 3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "0 aziendale NaN 01.05.2019 31.08.2022 \n", + "1 aziendale NaN 01.05.2019 31.08.2022 \n", + "2 comunale Laives 01.09.2020 31.08.2022 \n", + "3 aziendale NaN 01.10.2018 31.08.2021 \n", + "4 aziendale NaN 01.10.2018 31.08.2021 \n", + "5 aziendale NaN 02.04.2019 31.08.2020 \n", + "6 aziendale NaN 02.04.2019 31.08.2020 \n", + "7 aziendale NaN 02.09.2019 31.08.2021 \n", + "8 aziendale NaN 02.09.2019 31.08.2021 \n", + "12 comunale Laives 02.10.2017 27.07.2020 \n", + "11 comunale Laives 02.10.2017 27.07.2020 \n", + "9 comunale Laives 02.10.2017 27.07.2020 \n", + "10 comunale Laives 02.10.2017 27.07.2020 \n", + "13 aziendale NaN 03.01.2020 31.08.2021 \n", + "14 aziendale NaN 03.02.2019 08.02.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "16 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "17 aziendale NaN 05.07.2018 31.08.2020 \n", + "18 aziendale NaN 05.07.2018 31.08.2020 \n", + "19 comunale Laives 05.10.2020 31.12.2021 \n", + "20 aziendale NaN 06.09.2018 30.09.2020 \n", + "21 aziendale NaN 06.09.2018 30.09.2020 \n", + "22 comunale Laives 07.01.2019 31.08.2021 \n", + "23 comunale Laives 07.01.2019 31.08.2021 \n", + "25 comunale Laives 07.03.2019 31.08.2021 \n", + "24 comunale Laives 07.03.2019 31.08.2021 \n", + "26 aziendale NaN 07.09.2020 31.08.2021 \n", + "27 aziendale NaN 08.01.2020 31.08.2022 \n", + "28 aziendale NaN 08.09.2020 31.08.2022 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Vadena 10.09.2018 31.08.2020 \n", + "31 comunale Vadena 10.09.2018 31.08.2020 \n", + "32 aziendale NaN 11.12.2017 31.08.2020 \n", + "33 aziendale NaN 11.12.2017 31.08.2020 \n", + "34 aziendale NaN 13.01.2020 31.12.2020 \n", + "35 aziendale NaN 15.11.2020 31.08.2021 \n", + "37 comunale Lana 16.08.2018 31.08.2020 \n", + "36 comunale Lana 16.08.2018 31.08.2020 \n", + "39 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "38 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "40 comunale Merano 17.09.2018 31.08.2020 \n", + "41 comunale Nalles 17.09.2018 31.08.2020 \n", + "42 aziendale NaN 20.08.2020 31.08.2023 \n", + "43 aziendale NaN 23.08.2018 31.08.2021 \n", + "44 aziendale NaN 23.08.2018 31.08.2021 \n", + "45 aziendale NaN 26.11.2018 31.08.2020 \n", + "46 aziendale NaN 26.11.2018 31.08.2020 \n", + "47 aziendale NaN 27.01.2020 31.06.2021 \n", + "48 comunale Tesimo 27.05.2019 31.08.2021 \n", + "49 comunale Tesimo 27.05.2019 31.08.2021 \n", + "50 comunale Laives 27.08.2018 31.08.2020 \n", + "51 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 209, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd1e563f", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"ore666\"] = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2efa6f7", + "metadata": {}, + "outputs": [], + "source": [ + "df1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5416ddec", + "metadata": {}, + "outputs": [], + "source": [ + "df2[\"DataFine\"].dt.strftime('%m/%d/%Y')" + ] + }, + { + "cell_type": "code", + "execution_count": 282, + "id": "c499fea1", + "metadata": {}, + "outputs": [], + "source": [ + "del df2" + ] + }, + { + "cell_type": "code", + "execution_count": 283, + "id": "068a705b", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'df2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [283]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf2\u001b[49m\n", + "\u001b[0;31mNameError\u001b[0m: name 'df2' is not defined" + ] + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 285, + "id": "92273887", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['index', 'Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 285, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c18559e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 287, + "id": "61c75dfe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/home/stfz/notebooks/max/pages/Jupyter'" + ] + }, + "execution_count": 287, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 289, + "id": "3166175f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/stfz/notebooks/max\n" + ] + } + ], + "source": [ + "cd .." + ] + }, + { + "cell_type": "code", + "execution_count": 290, + "id": "2261bc84", + "metadata": {}, + "outputs": [], + "source": [ + "dfg = pd.read_excel(\"GemeindenComuni.xlsx\")" + ] + }, + { + "cell_type": "code", + "execution_count": 293, + "id": "ff252390", + "metadata": {}, + "outputs": [], + "source": [ + "c1 = dfx[\"ComuneProvenienza\"].isin(dfg[\"Gemeinde\"])\n", + "c2 = dfx[\"ComuneProvenienza\"].isin(dfg[\"Comune\"])\n", + "c = c1 | c2" + ] + }, + { + "cell_type": "code", + "execution_count": 294, + "id": "72f08d92", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16 False\n", + "14 False\n", + "36 False\n", + "37 False\n", + "0 True\n", + "34 False\n", + "9 False\n", + "12 False\n", + "6 True\n", + "7 True\n", + "4 True\n", + "10 False\n", + "21 True\n", + "5 True\n", + "30 False\n", + "13 False\n", + "8 True\n", + "3 True\n", + "Name: ComuneProvenienza, dtype: bool" + ] + }, + "execution_count": 294, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "c" + ] + }, + { + "cell_type": "code", + "execution_count": 295, + "id": "44ae9143", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 " + ] + }, + "execution_count": 295, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx[~c]" + ] + }, + { + "cell_type": "code", + "execution_count": 298, + "id": "ddad26b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 False\n", + "1 False\n", + "2 False\n", + "3 False\n", + "4 False\n", + " ... \n", + "111 False\n", + "112 False\n", + "113 False\n", + "114 False\n", + "115 False\n", + "Name: Gemeinde, Length: 116, dtype: bool" + ] + }, + "execution_count": 298, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfg[\"Gemeinde\"] == \"Neumarkt\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "accbf103", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/1-prospetto rendicontazione microstrutture miste 2020.xlsx b/pages/Jupyter/1-prospetto rendicontazione microstrutture miste 2020.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e61a24af74d38472edc8538434a1707e88de3a50 Binary files /dev/null and b/pages/Jupyter/1-prospetto rendicontazione microstrutture miste 2020.xlsx differ diff --git a/pages/Jupyter/BambinoPiuComuni.ipynb b/pages/Jupyter/BambinoPiuComuni.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..2ccc5d55023badecbb4a54f9973cc2daa2b82228 --- /dev/null +++ b/pages/Jupyter/BambinoPiuComuni.ipynb @@ -0,0 +1,1662 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "983fbdd8", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "4f45a796", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Trägerkörperschaft:NaNNaNNaNSozialgenossenschaft Tagesmütter - Gen.NaNNaNNaNNaNNaNNaNNaNNaN
3Wohnsitzgemeinde bzg. Gemeinde des ständigen A...NaNNaNNaNEppan a.d. Weinstr.NaNNaNNaNNaNNaNNaNNaNNaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
7Fortlaufende\\nNummerNachname und Vorname des KindesGeburtsdatumSteuernummerTagesmutterWohnsitzgemeinde der TagesmutterDatum Vertragsbeginn (oder Datum Beginn der Be...Datum Vertragsende \\n(oder Datum Ende der Betr...Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Vertraglich vereinbarte aber nicht erbrachte B...Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt
819ANZELONI AURELIA2017-05-07 00:00:00NZLRLA17E47A952ICAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2017-09-04 00:00:002020-06-19 00:00:00194.25381NaN314889.25
953BOCK FELIX2017-03-15 00:00:00BCKFLX17C15F132XVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2018-03-19 00:00:002020-08-28 00:00:00150288NaN159597
1063BRIGL HELENA2020-02-14 00:00:00BRGHLN20B54F132KRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2020-08-31 00:00:002023-02-10 00:00:00269.7525NaN0294.75
1182CHRISTOF DAVID2017-05-15 00:00:00CHRDVD17E15A952TCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-09-03 00:00:002020-06-16 00:00:00183.5326NaN269778.5
1283COCCA BENJAMIN2018-02-16 00:00:00CCCBJM18B16A952XRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-08-27 00:00:00565150NaN0.5715.5
1394DEJORI SIMON2019-03-02 00:00:00DJRSMN19C02A952TCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2019-09-02 00:00:002022-08-26 00:00:00777259.75NaN81044.75
14113FABI EMILIA2019-08-08 00:00:00FBAMLE19M48A952MWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2020-09-21 00:00:002022-09-02 00:00:002220NaN0222
15114FABI MARIE (TM)2016-12-20 00:00:00FBAMRA16T60F132XLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-04 00:00:002020-02-04 00:00:00630NaN063
16121FEDERA ALEX2017-07-28 00:00:00FDRLXA17L28A952TKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-21 00:00:002020-09-11 00:00:00412359NaN99.5870.5
17122FEDERA EMMA2020-02-11 00:00:00FDRMME20B51A952VKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2020-09-14 00:00:002021-12-31 00:00:0034726NaN0373
18135FINK ELLA2019-09-30 00:00:00FNKLLE19P70A952UKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2020-08-31 00:00:002022-09-02 00:00:00298.7527NaN0325.75
19145FRAU AARON2018-07-05 00:00:00FRARNA18L05A952ULANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-01 00:00:002021-06-25 00:00:00520150NaN89759
20187GRIESSMAIR SIMON2017-06-30 00:00:00GRSSMN17H30F132ECAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-02-08 00:00:002020-05-26 00:00:00208443NaNNaN651
21198HEISS JONAS2017-04-07 00:00:00HSSJNS17D07F132IPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2019-07-29 00:00:002020-06-09 00:00:00161240NaN152553
22211HOELBING FLIRI LOU2018-04-24 00:00:00HLBFRL18D24A952FVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-01-28 00:00:000216NaN101.75317.75
23212HOELBING FLIRI LOU2018-04-24 00:00:00HLBFRL18D24A952FLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-02-18 00:00:002021-01-28 00:00:00409.75-10NaN0399.75
24217HOFER FIONA2018-03-05 00:00:00HFRFNI18C45A952UVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:000216NaN119335
25218HOFER FIONA2018-03-05 00:00:00HFRFNI18C45A952UWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:00315.259NaN0324.25
26223HOFER OLIVIA2018-03-05 00:00:00HFRLVO18C45A952WVON DELLEMANN ANNAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:000216NaN119335
27224HOFER OLIVIA2018-03-05 00:00:00HFRLVO18C45A952WWEGMANN NADYAEppan a.d. Weinstr./Appiano s.s.d.v.2019-10-07 00:00:002021-02-28 00:00:00315.259NaN0324.25
28240KAGER TONI2018-05-09 00:00:00KGRTNO18E09A952IRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-15 00:00:002021-08-27 00:00:00749.25219.5NaN30998.75
29250KNAPP MARTIN2019-08-09 00:00:00KNPMTN19M09C372WCAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2020-06-08 00:00:002022-09-02 00:00:00476.525NaN-177.5324
30252KOESSLER JOHAN2019-01-02 00:00:00KSSJHN19A02A952NKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-04-01 00:00:002022-08-26 00:00:00513173NaN122808
31275LOBIS MANUEL2018-07-26 00:00:00LBSMNL18L26A952QLANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-05-13 00:00:002021-09-03 00:00:00625170NaN-54741
32282MADEDDU DAVIS2017-01-08 00:00:00MDDDVS17A08A952NPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2018-01-08 00:00:002020-06-26 00:00:00150.75192NaN97439.75
33302MARSEILER NELLY2018-07-07 00:00:00MRSNLY18L47F132ERABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-19 00:00:002021-01-29 00:00:00627126.75NaN-9.25744.5
34305MASCALZONI MASSIMILIANO2017-04-10 00:00:00MSCMSM17D10A952UPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2018-02-19 00:00:002020-08-28 00:00:00203168NaN9380
35318MESSNER ELIN2017-07-27 00:00:00MSSLNE17L67F132ALANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-01-07 00:00:002020-09-04 00:00:00294165NaN14473
36319MESSNER MARTIN2018-07-29 00:00:00MSSMTN18L29B160ALANTHALER UTEEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-26 00:00:002021-09-03 00:00:00809250NaN1001159
37354OHNEWEIN RUDI2018-09-08 00:00:00HNWRDU18P08A952BKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-03-04 00:00:002021-08-27 00:00:00654.5252NaN9915.5
38363PEER PHILIPP RYAN2018-06-28 00:00:00PREPLP18H28A952KPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2019-08-26 00:00:002021-08-27 00:00:00552236NaN28816
39384PINTO FRANZISKA2019-01-29 00:00:00PNTFNZ19A69A952SKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-09-09 00:00:002021-08-27 00:00:00544167NaN-33.5677.5
40407RAIFER LISA2018-04-09 00:00:00RFRLSI18D49A952TRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2020-07-13 00:00:002021-08-27 00:00:00513.516NaN-143386.5
41507UNTERWEGER SIMON2018-03-30 00:00:00NTRSMN18C30F132WKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2019-04-01 00:00:002021-09-03 00:00:00397.25251NaN69.75718
42514VIAN SOFIA2019-05-24 00:00:00VNISFO19E64A952VPLATTNER HELENEEppan a.d. Weinstr./Appiano s.s.d.v.2020-02-03 00:00:002022-08-26 00:00:00636.75360NaN541050.75
43515VIEHWEIDER PAUL2017-06-20 00:00:00VHWPLA17H20A952MRABANSER HELGAEppan a.d. Weinstr./Appiano s.s.d.v.2018-09-17 00:00:002020-08-28 00:00:00243135NaN15.5393.5
44524WALTER MARION2017-03-12 00:00:00WLTMRN17C52A952DKIER CLAUDIAEppan a.d. Weinstr./Appiano s.s.d.v.2018-01-08 00:00:002020-08-28 00:00:00442.5348NaN73.25863.75
45551ZUBLASING EVA2017-08-16 00:00:00ZBLVEA17M56A952ECAPPELLO MARGARETHEppan a.d. Weinstr./Appiano s.s.d.v.2018-10-01 00:00:002020-06-25 00:00:0084163NaN128375
46SummeNaNNaNNaNNaNNaNNaNNaN13926.567480176322437.5
47NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
48* bei eventuellen Betreuungsverträgen, welche ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
49NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
50NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
51NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
52Dieser Jahresbericht entspricht dem Original, ...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
53NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
54Unterschrift des/der gesetzlichen Vertreters/i...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Trägerkörperschaft: \n", + "3 Wohnsitzgemeinde bzg. Gemeinde des ständigen A... \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Fortlaufende\\nNummer \n", + "8 19 \n", + "9 53 \n", + "10 63 \n", + "11 82 \n", + "12 83 \n", + "13 94 \n", + "14 113 \n", + "15 114 \n", + "16 121 \n", + "17 122 \n", + "18 135 \n", + "19 145 \n", + "20 187 \n", + "21 198 \n", + "22 211 \n", + "23 212 \n", + "24 217 \n", + "25 218 \n", + "26 223 \n", + "27 224 \n", + "28 240 \n", + "29 250 \n", + "30 252 \n", + "31 275 \n", + "32 282 \n", + "33 302 \n", + "34 305 \n", + "35 318 \n", + "36 319 \n", + "37 354 \n", + "38 363 \n", + "39 384 \n", + "40 407 \n", + "41 507 \n", + "42 514 \n", + "43 515 \n", + "44 524 \n", + "45 551 \n", + "46 Summe \n", + "47 NaN \n", + "48 * bei eventuellen Betreuungsverträgen, welche ... \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 Dieser Jahresbericht entspricht dem Original, ... \n", + "53 NaN \n", + "54 Unterschrift des/der gesetzlichen Vertreters/i... \n", + "\n", + " Cognome e nome bambino Data di nascita Codice fiscale \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 NaN NaN NaN \n", + "5 NaN NaN NaN \n", + "6 NaN NaN NaN \n", + "7 Nachname und Vorname des Kindes Geburtsdatum Steuernummer \n", + "8 ANZELONI AURELIA 2017-05-07 00:00:00 NZLRLA17E47A952I \n", + "9 BOCK FELIX 2017-03-15 00:00:00 BCKFLX17C15F132X \n", + "10 BRIGL HELENA 2020-02-14 00:00:00 BRGHLN20B54F132K \n", + "11 CHRISTOF DAVID 2017-05-15 00:00:00 CHRDVD17E15A952T \n", + "12 COCCA BENJAMIN 2018-02-16 00:00:00 CCCBJM18B16A952X \n", + "13 DEJORI SIMON 2019-03-02 00:00:00 DJRSMN19C02A952T \n", + "14 FABI EMILIA 2019-08-08 00:00:00 FBAMLE19M48A952M \n", + "15 FABI MARIE (TM) 2016-12-20 00:00:00 FBAMRA16T60F132X \n", + "16 FEDERA ALEX 2017-07-28 00:00:00 FDRLXA17L28A952T \n", + "17 FEDERA EMMA 2020-02-11 00:00:00 FDRMME20B51A952V \n", + "18 FINK ELLA 2019-09-30 00:00:00 FNKLLE19P70A952U \n", + "19 FRAU AARON 2018-07-05 00:00:00 FRARNA18L05A952U \n", + "20 GRIESSMAIR SIMON 2017-06-30 00:00:00 GRSSMN17H30F132E \n", + "21 HEISS JONAS 2017-04-07 00:00:00 HSSJNS17D07F132I \n", + "22 HOELBING FLIRI LOU 2018-04-24 00:00:00 HLBFRL18D24A952F \n", + "23 HOELBING FLIRI LOU 2018-04-24 00:00:00 HLBFRL18D24A952F \n", + "24 HOFER FIONA 2018-03-05 00:00:00 HFRFNI18C45A952U \n", + "25 HOFER FIONA 2018-03-05 00:00:00 HFRFNI18C45A952U \n", + "26 HOFER OLIVIA 2018-03-05 00:00:00 HFRLVO18C45A952W \n", + "27 HOFER OLIVIA 2018-03-05 00:00:00 HFRLVO18C45A952W \n", + "28 KAGER TONI 2018-05-09 00:00:00 KGRTNO18E09A952I \n", + "29 KNAPP MARTIN 2019-08-09 00:00:00 KNPMTN19M09C372W \n", + "30 KOESSLER JOHAN 2019-01-02 00:00:00 KSSJHN19A02A952N \n", + "31 LOBIS MANUEL 2018-07-26 00:00:00 LBSMNL18L26A952Q \n", + "32 MADEDDU DAVIS 2017-01-08 00:00:00 MDDDVS17A08A952N \n", + "33 MARSEILER NELLY 2018-07-07 00:00:00 MRSNLY18L47F132E \n", + "34 MASCALZONI MASSIMILIANO 2017-04-10 00:00:00 MSCMSM17D10A952U \n", + "35 MESSNER ELIN 2017-07-27 00:00:00 MSSLNE17L67F132A \n", + "36 MESSNER MARTIN 2018-07-29 00:00:00 MSSMTN18L29B160A \n", + "37 OHNEWEIN RUDI 2018-09-08 00:00:00 HNWRDU18P08A952B \n", + "38 PEER PHILIPP RYAN 2018-06-28 00:00:00 PREPLP18H28A952K \n", + "39 PINTO FRANZISKA 2019-01-29 00:00:00 PNTFNZ19A69A952S \n", + "40 RAIFER LISA 2018-04-09 00:00:00 RFRLSI18D49A952T \n", + "41 UNTERWEGER SIMON 2018-03-30 00:00:00 NTRSMN18C30F132W \n", + "42 VIAN SOFIA 2019-05-24 00:00:00 VNISFO19E64A952V \n", + "43 VIEHWEIDER PAUL 2017-06-20 00:00:00 VHWPLA17H20A952M \n", + "44 WALTER MARION 2017-03-12 00:00:00 WLTMRN17C52A952D \n", + "45 ZUBLASING EVA 2017-08-16 00:00:00 ZBLVEA17M56A952E \n", + "46 NaN NaN NaN \n", + "47 NaN NaN NaN \n", + "48 NaN NaN NaN \n", + "49 NaN NaN NaN \n", + "50 NaN NaN NaN \n", + "51 NaN NaN NaN \n", + "52 NaN NaN NaN \n", + "53 NaN NaN NaN \n", + "54 NaN NaN NaN \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 Sozialgenossenschaft Tagesmütter - Gen. \n", + "3 Eppan a.d. Weinstr. \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Tagesmutter \n", + "8 CAPPELLO MARGARETH \n", + "9 VON DELLEMANN ANNA \n", + "10 RABANSER HELGA \n", + "11 CAPPELLO MARGARETH \n", + "12 RABANSER HELGA \n", + "13 CAPPELLO MARGARETH \n", + "14 WEGMANN NADYA \n", + "15 LANTHALER UTE \n", + "16 KIER CLAUDIA \n", + "17 KIER CLAUDIA \n", + "18 KIER CLAUDIA \n", + "19 LANTHALER UTE \n", + "20 CAPPELLO MARGARETH \n", + "21 PLATTNER HELENE \n", + "22 VON DELLEMANN ANNA \n", + "23 LANTHALER UTE \n", + "24 VON DELLEMANN ANNA \n", + "25 WEGMANN NADYA \n", + "26 VON DELLEMANN ANNA \n", + "27 WEGMANN NADYA \n", + "28 RABANSER HELGA \n", + "29 CAPPELLO MARGARETH \n", + "30 KIER CLAUDIA \n", + "31 LANTHALER UTE \n", + "32 PLATTNER HELENE \n", + "33 RABANSER HELGA \n", + "34 PLATTNER HELENE \n", + "35 LANTHALER UTE \n", + "36 LANTHALER UTE \n", + "37 KIER CLAUDIA \n", + "38 PLATTNER HELENE \n", + "39 KIER CLAUDIA \n", + "40 RABANSER HELGA \n", + "41 KIER CLAUDIA \n", + "42 PLATTNER HELENE \n", + "43 RABANSER HELGA \n", + "44 KIER CLAUDIA \n", + "45 CAPPELLO MARGARETH \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Wohnsitzgemeinde der Tagesmutter \n", + "8 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "9 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "10 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "11 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "12 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "13 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "14 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "15 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "16 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "17 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "18 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "19 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "20 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "21 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "22 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "23 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "24 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "25 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "26 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "27 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "28 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "29 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "30 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "31 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "32 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "33 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "34 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "35 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "36 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "37 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "38 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "39 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "40 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "41 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "42 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "43 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "44 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "45 Eppan a.d. Weinstr./Appiano s.s.d.v. \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsbeginn (oder Datum Beginn der Be... \n", + "8 2017-09-04 00:00:00 \n", + "9 2018-03-19 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2018-09-03 00:00:00 \n", + "12 2019-02-18 00:00:00 \n", + "13 2019-09-02 00:00:00 \n", + "14 2020-09-21 00:00:00 \n", + "15 2019-02-04 00:00:00 \n", + "16 2019-10-21 00:00:00 \n", + "17 2020-09-14 00:00:00 \n", + "18 2020-08-31 00:00:00 \n", + "19 2018-10-01 00:00:00 \n", + "20 2018-02-08 00:00:00 \n", + "21 2019-07-29 00:00:00 \n", + "22 2019-02-18 00:00:00 \n", + "23 2019-02-18 00:00:00 \n", + "24 2019-10-07 00:00:00 \n", + "25 2019-10-07 00:00:00 \n", + "26 2019-10-07 00:00:00 \n", + "27 2019-10-07 00:00:00 \n", + "28 2018-10-15 00:00:00 \n", + "29 2020-06-08 00:00:00 \n", + "30 2019-04-01 00:00:00 \n", + "31 2019-05-13 00:00:00 \n", + "32 2018-01-08 00:00:00 \n", + "33 2019-08-19 00:00:00 \n", + "34 2018-02-19 00:00:00 \n", + "35 2019-01-07 00:00:00 \n", + "36 2019-08-26 00:00:00 \n", + "37 2019-03-04 00:00:00 \n", + "38 2019-08-26 00:00:00 \n", + "39 2019-09-09 00:00:00 \n", + "40 2020-07-13 00:00:00 \n", + "41 2019-04-01 00:00:00 \n", + "42 2020-02-03 00:00:00 \n", + "43 2018-09-17 00:00:00 \n", + "44 2018-01-08 00:00:00 \n", + "45 2018-10-01 00:00:00 \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Datum Vertragsende \\n(oder Datum Ende der Betr... \n", + "8 2020-06-19 00:00:00 \n", + "9 2020-08-28 00:00:00 \n", + "10 2023-02-10 00:00:00 \n", + "11 2020-06-16 00:00:00 \n", + "12 2021-08-27 00:00:00 \n", + "13 2022-08-26 00:00:00 \n", + "14 2022-09-02 00:00:00 \n", + "15 2020-02-04 00:00:00 \n", + "16 2020-09-11 00:00:00 \n", + "17 2021-12-31 00:00:00 \n", + "18 2022-09-02 00:00:00 \n", + "19 2021-06-25 00:00:00 \n", + "20 2020-05-26 00:00:00 \n", + "21 2020-06-09 00:00:00 \n", + "22 2021-01-28 00:00:00 \n", + "23 2021-01-28 00:00:00 \n", + "24 2021-02-28 00:00:00 \n", + "25 2021-02-28 00:00:00 \n", + "26 2021-02-28 00:00:00 \n", + "27 2021-02-28 00:00:00 \n", + "28 2021-08-27 00:00:00 \n", + "29 2022-09-02 00:00:00 \n", + "30 2022-08-26 00:00:00 \n", + "31 2021-09-03 00:00:00 \n", + "32 2020-06-26 00:00:00 \n", + "33 2021-01-29 00:00:00 \n", + "34 2020-08-28 00:00:00 \n", + "35 2020-09-04 00:00:00 \n", + "36 2021-09-03 00:00:00 \n", + "37 2021-08-27 00:00:00 \n", + "38 2021-08-27 00:00:00 \n", + "39 2021-08-27 00:00:00 \n", + "40 2021-08-27 00:00:00 \n", + "41 2021-09-03 00:00:00 \n", + "42 2022-08-26 00:00:00 \n", + "43 2020-08-28 00:00:00 \n", + "44 2020-08-28 00:00:00 \n", + "45 2020-06-25 00:00:00 \n", + "46 NaN \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Betreuungs-\\nstunden\\nlaut Beschluss \\nNr. 666... \n", + "8 194.25 \n", + "9 150 \n", + "10 269.75 \n", + "11 183.5 \n", + "12 565 \n", + "13 777 \n", + "14 222 \n", + "15 63 \n", + "16 412 \n", + "17 347 \n", + "18 298.75 \n", + "19 520 \n", + "20 208 \n", + "21 161 \n", + "22 0 \n", + "23 409.75 \n", + "24 0 \n", + "25 315.25 \n", + "26 0 \n", + "27 315.25 \n", + "28 749.25 \n", + "29 476.5 \n", + "30 513 \n", + "31 625 \n", + "32 150.75 \n", + "33 627 \n", + "34 203 \n", + "35 294 \n", + "36 809 \n", + "37 654.5 \n", + "38 552 \n", + "39 544 \n", + "40 513.5 \n", + "41 397.25 \n", + "42 636.75 \n", + "43 243 \n", + "44 442.5 \n", + "45 84 \n", + "46 13926.5 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 381 \n", + "9 288 \n", + "10 25 \n", + "11 326 \n", + "12 150 \n", + "13 259.75 \n", + "14 0 \n", + "15 0 \n", + "16 359 \n", + "17 26 \n", + "18 27 \n", + "19 150 \n", + "20 443 \n", + "21 240 \n", + "22 216 \n", + "23 -10 \n", + "24 216 \n", + "25 9 \n", + "26 216 \n", + "27 9 \n", + "28 219.5 \n", + "29 25 \n", + "30 173 \n", + "31 170 \n", + "32 192 \n", + "33 126.75 \n", + "34 168 \n", + "35 165 \n", + "36 250 \n", + "37 252 \n", + "38 236 \n", + "39 167 \n", + "40 16 \n", + "41 251 \n", + "42 360 \n", + "43 135 \n", + "44 348 \n", + "45 163 \n", + "46 6748 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 NaN \n", + "9 NaN \n", + "10 NaN \n", + "11 NaN \n", + "12 NaN \n", + "13 NaN \n", + "14 NaN \n", + "15 NaN \n", + "16 NaN \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "20 NaN \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "37 NaN \n", + "38 NaN \n", + "39 NaN \n", + "40 NaN \n", + "41 NaN \n", + "42 NaN \n", + "43 NaN \n", + "44 NaN \n", + "45 NaN \n", + "46 0 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Vertraglich vereinbarte aber nicht erbrachte B... \n", + "8 314 \n", + "9 159 \n", + "10 0 \n", + "11 269 \n", + "12 0.5 \n", + "13 8 \n", + "14 0 \n", + "15 0 \n", + "16 99.5 \n", + "17 0 \n", + "18 0 \n", + "19 89 \n", + "20 NaN \n", + "21 152 \n", + "22 101.75 \n", + "23 0 \n", + "24 119 \n", + "25 0 \n", + "26 119 \n", + "27 0 \n", + "28 30 \n", + "29 -177.5 \n", + "30 122 \n", + "31 -54 \n", + "32 97 \n", + "33 -9.25 \n", + "34 9 \n", + "35 14 \n", + "36 100 \n", + "37 9 \n", + "38 28 \n", + "39 -33.5 \n", + "40 -143 \n", + "41 69.75 \n", + "42 54 \n", + "43 15.5 \n", + "44 73.25 \n", + "45 128 \n", + "46 1763 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + "5 NaN \n", + "6 NaN \n", + "7 Abgerechnete Betreuungs-\\nstunden \\n2020\\ngesamt \n", + "8 889.25 \n", + "9 597 \n", + "10 294.75 \n", + "11 778.5 \n", + "12 715.5 \n", + "13 1044.75 \n", + "14 222 \n", + "15 63 \n", + "16 870.5 \n", + "17 373 \n", + "18 325.75 \n", + "19 759 \n", + "20 651 \n", + "21 553 \n", + "22 317.75 \n", + "23 399.75 \n", + "24 335 \n", + "25 324.25 \n", + "26 335 \n", + "27 324.25 \n", + "28 998.75 \n", + "29 324 \n", + "30 808 \n", + "31 741 \n", + "32 439.75 \n", + "33 744.5 \n", + "34 380 \n", + "35 473 \n", + "36 1159 \n", + "37 915.5 \n", + "38 816 \n", + "39 677.5 \n", + "40 386.5 \n", + "41 718 \n", + "42 1050.75 \n", + "43 393.5 \n", + "44 863.75 \n", + "45 375 \n", + "46 22437.5 \n", + "47 NaN \n", + "48 NaN \n", + "49 NaN \n", + "50 NaN \n", + "51 NaN \n", + "52 NaN \n", + "53 NaN \n", + "54 NaN " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faee8890", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true, + "vscode": { + "interpreter": { + "hash": "cf88d51bb359ca37aedeb3142437aa276b0f8132792620ce365bf5562ef1b43f" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git "a/pages/Jupyter/BambinoPiu\314\200Volte.ipynb" "b/pages/Jupyter/BambinoPiu\314\200Volte.ipynb" new file mode 100644 index 0000000000000000000000000000000000000000..6e5901694e5ecedde7095284e085775ec26acde3 --- /dev/null +++ "b/pages/Jupyter/BambinoPiu\314\200Volte.ipynb" @@ -0,0 +1,762 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "#import streamlit as st\n", + "import datetime as dt\n", + "from collections import Counter\n", + "fn = './errorfiles/storico.xlsx'\n", + "#fn = './errorfiles/Erklärung_Gemeinde_Aldein_2020.xlsx'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "afbfb93b", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'pd' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m df \u001b[38;5;241m=\u001b[39m \u001b[43mpd\u001b[49m\u001b[38;5;241m.\u001b[39mread_excel(fn)\n", + "\u001b[0;31mNameError\u001b[0m: name 'pd' is not defined" + ] + } + ], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c74655a1", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8fa5aeb6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2020 Ente gestore:\n", + "Unnamed: 1 NaN\n", + "Unnamed: 2 NaN\n", + "Unnamed: 3 Soc. Coop. Casa Bimbo Tagesmutter Onlus\n", + "Unnamed: 4 NaN\n", + "Unnamed: 5 NaN\n", + "Unnamed: 6 NaN\n", + "Unnamed: 7 NaN\n", + "Unnamed: 8 NaN\n", + "Unnamed: 9 NaN\n", + "Unnamed: 10 NaN\n", + "Unnamed: 11 NaN\n", + "Unnamed: 12 NaN\n", + "Name: 2, dtype: object" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger = df.iloc[2]\n", + "traeger" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "175c2512", + "metadata": {}, + "outputs": [], + "source": [ + "if type(traeger[4]) == type('string'):\n", + " print(\"ok\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "ae3e6a9c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Soc. Coop. Casa Bimbo Tagesmutter Onlus'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger = df.iloc[2]\n", + "t = traeger[3].title()\n", + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "8b8e1be3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type('string')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "84a3cd04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Bolzano'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde=df.iloc[3]\n", + "gemeinde[3]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "d0de814a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Soc. Coop. Casa Bimbo Tagesmutter Onlus'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "5e748143", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "45eb114d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020'],\n", + " dtype='object')" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = df.drop(labels=range(0,8), axis=0)\n", + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")\n", + "validi = df[\"Numero \\nprogressivo\"].notna()\n", + "df = df[validi]\n", + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "8c8b5a46", + "metadata": {}, + "outputs": [], + "source": [ + "c = df.groupby('Codice fiscale')['Codice fiscale'].transform('count') > 1" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "5ee368c2", + "metadata": {}, + "outputs": [], + "source": [ + "c2 = df.groupby('Codice fiscale')['Ore totali rendicontate per il 2020'].transform('sum') > 1920" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "eefd3928", + "metadata": {}, + "outputs": [], + "source": [ + "c3 = c & c2" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "f8f30c27", + "metadata": {}, + "outputs": [], + "source": [ + "c3 = df['Cognome e nome bambino'] == \"BILAL SHAMIR\"" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "17e972cd", + "metadata": {}, + "outputs": [], + "source": [ + "c4 = c3 & c" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "b53c26c8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
4435.0BILAL SHAMIR2018-05-11 00:00:00BLLSMR18E11A952NMILITARU ROXANABOLZANO2020-08-03 00:00:002020-09-02 00:00:00640NaNNaN64
4535.0BILAL SHAMIR2018-05-11 00:00:00BLLSMR18E11A952NCARUSO MARIABOLZANO2020-09-03 00:00:002021-08-27 00:00:002131616NaN245
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "44 35.0 BILAL SHAMIR 2018-05-11 00:00:00 \n", + "45 35.0 BILAL SHAMIR 2018-05-11 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "44 BLLSMR18E11A952N MILITARU ROXANA \n", + "45 BLLSMR18E11A952N CARUSO MARIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "44 2020-08-03 00:00:00 \n", + "45 2020-09-03 00:00:00 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "44 2020-09-02 00:00:00 \n", + "45 2021-08-27 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "44 64 \n", + "45 213 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "44 0 \n", + "45 16 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "44 NaN \n", + "45 16 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "44 NaN \n", + "45 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "44 64 \n", + "45 245 " + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[c3]" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "0d61314f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"['c' 't' 'm' 'c' 'c' 'e' 'm' 'd' 'h' 'r' 'b' 's' 'c' 'c' 's' 'd' 'm' 's'\\n 'e' 's' 'b' 't' 'r' 'm' 'e' 'e' 'e' 'm' 't' 'c' 'r' 'a' 'l' 's' 'm' 'r'\\n 'e' 'e' 'm' 't' 's' 'm' 'e' '2' 'm' 'h' 'l' 'd' 'a' 'r' 'b' 'e' 'c' 'l'\\n 'b' 'b' 'e' 'r' 'b' 'c' 'p' 't' 'p' 'l' 'e' 'r' 'h' 't' 'r']\"" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str(df['Codice fiscale'].str[8:9].values).lower()" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "7e11ef95", + "metadata": {}, + "outputs": [], + "source": [ + " mesi = {'a':'01','b':'02','c':'03', 'd':'04', 'e':'05', 'h':'06','l':'07','m':'08','p':'09','r':'10','s':'11','t':'12'}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "82c5dd43", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'a': '01',\n", + " 'b': '02',\n", + " 'c': '03',\n", + " 'd': '04',\n", + " 'e': '05',\n", + " 'h': '06',\n", + " 'l': '07',\n", + " 'm': '08',\n", + " 'p': '09',\n", + " 'r': '10',\n", + " 's': '11',\n", + " 't': '12'}" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mesi" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "98fe9449", + "metadata": {}, + "outputs": [], + "source": [ + " codvalido = (\n", + " df[\"Codice fiscale\"].str.match(\n", + " \"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\\d\\d[A-Z|a-z]\\d\\d[A-Z|a-z]\\d\\d\\d[A-Z|a-z]\"\n", + " )\n", + " == True\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "33898517", + "metadata": {}, + "outputs": [], + "source": [ + "df['Data di nascita'] = df['Data di nascita'].astype(\"datetime64[ns]\")\n", + "dfcod = df[codvalido]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "e421d59e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 3\n", + "9 12\n", + "10 8\n", + "11 3\n", + "12 3\n", + " ..\n", + "72 5\n", + "73 10\n", + "74 6\n", + "75 12\n", + "76 10\n", + "Name: Data di nascita, Length: 68, dtype: int64" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfcod[\"Data di nascita\"].dt.month" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "bbb14e0f", + "metadata": {}, + "outputs": [], + "source": [ + " anno = dfcod[\"Data di nascita\"].dt.year == 2000 + dfcod[\"Codice fiscale\"].str[\n", + " 6:8\n", + " ].astype(int)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "85083e02", + "metadata": {}, + "outputs": [], + "source": [ + "mese = dfcod[\"Data di nascita\"].dt.month == dfcod[\"Codice fiscale\"].str[8:9].astype('str').replace({'A':'1','B':'2','C':'3','D':'4', 'E':'5', 'H':'6','L':'7','M':'8','P':'9','R':'10','S':'11','T':'12'}).astype(int)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "eb95dde2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
4132.0GABRIELLI MIA2016-12-06GBRMIA16S63A952NMOSSA DANIELABOLZANO2019-09-23 00:00:002020-06-26 00:00:00148.5168NaN54370.5
7161.0SOTA PAOLA2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-23 00:00:002021-08-27 00:00:00667.25267.75NaN12.75947.75
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "41 32.0 GABRIELLI MIA 2016-12-06 \n", + "71 61.0 SOTA PAOLA 2018-08-29 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "41 GBRMIA16S63A952N MOSSA DANIELA \n", + "71 STOPLA18L69A952B MARTINELLO SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "41 BOLZANO \n", + "71 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "41 2019-09-23 00:00:00 \n", + "71 2019-09-23 00:00:00 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "41 2020-06-26 00:00:00 \n", + "71 2021-08-27 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "41 148.5 \n", + "71 667.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "41 168 \n", + "71 267.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "41 NaN \n", + "71 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "41 54 \n", + "71 12.75 \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "41 370.5 \n", + "71 947.75 " + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfcod[~mese]" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "929f5c8b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 3\n", + "9 12\n", + "10 8\n", + "11 3\n", + "12 3\n", + " ..\n", + "72 5\n", + "73 10\n", + "74 6\n", + "75 12\n", + "76 10\n", + "Name: Data di nascita, Length: 68, dtype: int64" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfcod[\"Data di nascita\"].dt.month" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f56eb19d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/ConteggioBimbiPerOreComune.ipynb b/pages/Jupyter/ConteggioBimbiPerOreComune.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..05f3178dbc7274d1aff0093aac1aa5eb1ad432ed --- /dev/null +++ b/pages/Jupyter/ConteggioBimbiPerOreComune.ipynb @@ -0,0 +1,3469 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 46, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "cd8dc6db", + "metadata": {}, + "outputs": [], + "source": [ + "ERRORDICT = {\n", + " # gestiamo tutto quello che riguarda i controlli da fare qui\n", + " # in seguito usiamo la key del dict per creare sia le checkbox\n", + " # sia per chiamare le funzioni, sia per creare la colonna bool\n", + " # per la tabella con soli errori\n", + " #\n", + " # in sostanza: vogliamo che ERRORDICT sia il riferimento unico\n", + " # per tutti i controlli che facciamo\n", + " #\n", + " # basta aggiungere qui un nuovo errore e la descrizione\n", + " # e i checkbox etc vengono creati automaticamente\n", + " \"errCodFisc1\": \"Controllo formato codice fiscale\",\n", + " \"errCodFisc2\": \"Controllo data nascita per codice fiscale\",\n", + " \"errAgeChild\": \"Controllo età bambino\",\n", + " \"errInizioMinoreFine\": \"Controllo date contrattuali\",\n", + " \"errErrorePresenza\": \"Controllo errore presenza\",\n", + " \"errErroreDati543\": \"Controllo errore dati 543\",\n", + " \"errFineAssistenzaMax4Anni\": \"Controllo fine contratto assistenza\",\n", + " \"errKindergarten_1\": \"Controllo Kindergarten #1\",\n", + " \"errKindergarten_2\": \"Controllo Kindergarten #2\",\n", + " \"errErroreFinanziamentoCompensativo\": \"Controllo finanziamento compensativo\",\n", + " \"errErroreFinanziamentoCompensativo2\": \"Controllo finanziamento compensativo #2\",\n", + " \"errErroreCovid\": \"Controllo Covid #1\",\n", + " \"errErroreCovid2\": \"Controllo Covid #2\",\n", + " \"errErroreCovid3\": \"Controllo Covid #3\",\n", + " \"errErroreCovid4\": \"Contratti lockdown sospetti (Covid #4)\",\n", + " \"errFehlerEingewöhnung\": \"Controllo Fehler Eingewöhnung\",\n", + " \"errFehlerEingewöhnung543Lockdown\": \"Controllo Fehler Eingewöhnung 543 Lockdown\",\n", + " \"errFehlerEingewöhnung543Notbetreuung\": \"Controllo Fehler Eingewöhnung 543 Notbetreuung\",\n", + " \"errGesamtstundenVertragszeitraum\": \"Controllo ore complessive periodo contrattuale\",\n", + " \"errSuperatoOreMassime1920\": \"Controllo ore complessive superiore a 1920\",\n", + " \"errBambinoInPiuComuni\": \"Bambino presente in più comuni\",\n", + " \"errPresentiAnnotazioni\": \"Bambini con annotazioni\",\n", + " \"errOreRendicontateZero\": \"Controllo ore rendicontate uguali a zero\",\n", + " \"massimo543\": \"Calcolo valore massimo ore 543\",\n", + " \"errSommaOre\": \"Calcolo somme per le ore riportate\",\n", + " \"errMassimoFC\": \"Calcolo valore massimo ore finanziamento compensativo\",\n", + " \"errCalcoloSomme\": \"Calcolo delle somme ore per comune\",\n", + " \"errCalcoloNumeroBimbi\": \"Calcolo numero bambini per comune\"\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"storico.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "da0c9f5f", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = df.groupby(\"Comune\",as_index=False).count()" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "d9d1fb9d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'filename', 'Cognome e nome bambino', 'Ente', 'Comune',\n", + " 'Data di nascita', 'Codice fiscale',\n", + " 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'massimo543',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'errCodFisc1', 'errCodFisc2',\n", + " 'errAgeChild', 'errInizioMinoreFine', 'errErrorePresenza',\n", + " 'errErroreDati543', 'errFineAssistenzaMax4Anni', 'errKindergarten_1',\n", + " 'errKindergarten_2', 'errErroreFinanziamentoCompensativo',\n", + " 'errErroreFinanziamentoCompensativo2', 'errErroreCovid',\n", + " 'errErroreCovid2', 'errErroreCovid3', 'errErroreCovid4',\n", + " 'errFehlerEingewöhnung', 'errFehlerEingewöhnung543Lockdown',\n", + " 'errFehlerEingewöhnung543Notbetreuung',\n", + " 'errGesamtstundenVertragszeitraum', 'errSuperatoOreMassime1920',\n", + " 'errBambinoInPiuComuni', 'errPresentiAnnotazioni',\n", + " 'errOreRendicontateZero', 'errSommaOre', 'errMassimoFC',\n", + " 'errCalcoloSomme', 'gg1', 'gg2', 'gg3', 'inizioNorm', 'fineNorm'],\n", + " dtype='object')" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "c5ae3d8c", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "ename": "KeyError", + "evalue": "\"['errCalcoloNumeroBimbi'] not found in axis\"", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [65]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m k \u001b[38;5;129;01min\u001b[39;00m ERRORDICT:\n\u001b[0;32m----> 2\u001b[0m df \u001b[38;5;241m=\u001b[39m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43mk\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43maxis\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/util/_decorators.py:311\u001b[0m, in \u001b[0;36mdeprecate_nonkeyword_arguments..decorate..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 305\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(args) \u001b[38;5;241m>\u001b[39m num_allow_args:\n\u001b[1;32m 306\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[1;32m 307\u001b[0m msg\u001b[38;5;241m.\u001b[39mformat(arguments\u001b[38;5;241m=\u001b[39marguments),\n\u001b[1;32m 308\u001b[0m \u001b[38;5;167;01mFutureWarning\u001b[39;00m,\n\u001b[1;32m 309\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39mstacklevel,\n\u001b[1;32m 310\u001b[0m )\n\u001b[0;32m--> 311\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/frame.py:4906\u001b[0m, in \u001b[0;36mDataFrame.drop\u001b[0;34m(self, labels, axis, index, columns, level, inplace, errors)\u001b[0m\n\u001b[1;32m 4774\u001b[0m \u001b[38;5;129m@deprecate_nonkeyword_arguments\u001b[39m(version\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, allowed_args\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mself\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlabels\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n\u001b[1;32m 4775\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdrop\u001b[39m(\n\u001b[1;32m 4776\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 4783\u001b[0m errors: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mraise\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 4784\u001b[0m ):\n\u001b[1;32m 4785\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 4786\u001b[0m \u001b[38;5;124;03m Drop specified labels from rows or columns.\u001b[39;00m\n\u001b[1;32m 4787\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 4904\u001b[0m \u001b[38;5;124;03m weight 1.0 0.8\u001b[39;00m\n\u001b[1;32m 4905\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 4906\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 4907\u001b[0m \u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4908\u001b[0m \u001b[43m \u001b[49m\u001b[43maxis\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4909\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4910\u001b[0m \u001b[43m \u001b[49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4911\u001b[0m \u001b[43m \u001b[49m\u001b[43mlevel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlevel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4912\u001b[0m \u001b[43m \u001b[49m\u001b[43minplace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minplace\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4913\u001b[0m \u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 4914\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:4150\u001b[0m, in \u001b[0;36mNDFrame.drop\u001b[0;34m(self, labels, axis, index, columns, level, inplace, errors)\u001b[0m\n\u001b[1;32m 4148\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m axis, labels \u001b[38;5;129;01min\u001b[39;00m axes\u001b[38;5;241m.\u001b[39mitems():\n\u001b[1;32m 4149\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m labels \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m-> 4150\u001b[0m obj \u001b[38;5;241m=\u001b[39m \u001b[43mobj\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_drop_axis\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlevel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlevel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4152\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m inplace:\n\u001b[1;32m 4153\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_update_inplace(obj)\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:4185\u001b[0m, in \u001b[0;36mNDFrame._drop_axis\u001b[0;34m(self, labels, axis, level, errors)\u001b[0m\n\u001b[1;32m 4183\u001b[0m new_axis \u001b[38;5;241m=\u001b[39m axis\u001b[38;5;241m.\u001b[39mdrop(labels, level\u001b[38;5;241m=\u001b[39mlevel, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[1;32m 4184\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 4185\u001b[0m new_axis \u001b[38;5;241m=\u001b[39m \u001b[43maxis\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdrop\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrors\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43merrors\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4186\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreindex(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m{axis_name: new_axis})\n\u001b[1;32m 4188\u001b[0m \u001b[38;5;66;03m# Case for non-unique axis\u001b[39;00m\n\u001b[1;32m 4189\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py:6017\u001b[0m, in \u001b[0;36mIndex.drop\u001b[0;34m(self, labels, errors)\u001b[0m\n\u001b[1;32m 6015\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mask\u001b[38;5;241m.\u001b[39many():\n\u001b[1;32m 6016\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m errors \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mignore\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m-> 6017\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mlabels[mask]\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not found in axis\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 6018\u001b[0m indexer \u001b[38;5;241m=\u001b[39m indexer[\u001b[38;5;241m~\u001b[39mmask]\n\u001b[1;32m 6019\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdelete(indexer)\n", + "\u001b[0;31mKeyError\u001b[0m: \"['errCalcoloNumeroBimbi'] not found in axis\"" + ] + } + ], + "source": [ + "for k in ERRORDICT:\n", + " df = df.drop([k],axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "b56e8492", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'filename', 'Cognome e nome bambino', 'Ente', 'Comune',\n", + " 'Data di nascita', 'Codice fiscale',\n", + " 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'gg1', 'gg2', 'gg3',\n", + " 'inizioNorm', 'fineNorm'],\n", + " dtype='object')" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "2a9a5d4e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0filenameCognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)...Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020gg1gg2gg3inizioNormfineNorm
011Erklärung_Gemeinde_Algund_2020.xlsxFLARER THEOSozialgenossenschaft Tagesmütter - Gen.Algund2018-07-11FLRTHE18L11F132ULADURNER JOHANNAMeran/Merano2020-03-02...459.00337.0000.5796.5074802020-03-022020-12-31
116Erklärung_Gemeinde_Algund_2020.xlsxMIRANDOLA LENZSozialgenossenschaft Tagesmütter - Gen.Algund2019-03-17MRNLNZ19C17F132ABRUNELLO CHRISTINEAlgund/Lagundo2020-11-09...74.5023.7500.098.250802020-11-092020-12-31
28Erklärung_Gemeinde_Branzoll_2020.xlsxCABULA LEONARDOSozialgenossenschaft Tagesmütter - Gen.Branzoll2017-07-24CBLLRD17L24A952HPUFF CHRISTINALeifers/Laives2020-01-27...1199.50348.0004.01551.5074822020-01-272020-12-31
39Erklärung_Gemeinde_Brixen_2020.xlsxALBERTI VICKYSozialgenossenschaft Tagesmütter - Gen.Brixen2017-11-03LBRVKY17S43B160UPUNER PAULAVahrn/Varna2018-09-03...884.25234.00024.51142.7574802020-01-012020-12-31
423Erklärung_Gemeinde_Brixen_2020.xlsxNITZ MIASozialgenossenschaft Tagesmütter - Gen.Brixen2017-10-06NTZMIA17R46B160FPUNER PAULAVahrn/Varna2018-09-24...868.50296.00029.01193.5074802020-01-012020-12-31
..................................................................
9110Erklärung_Gemeinde_Terenten_2020.xlsxINNERHOFER JULIANSozialgenossenschaft Tagesmütter - Gen.Terenten2017-01-17NNRJLN17A17B220YLECHNER MARTHATerenten/Terento2018-01-08...208.00406.0000.0614.0074002020-01-012020-06-26
928Erklärung_Gemeinde_Tscherms_2020.xlsxMAIRHOFER MARIESozialgenossenschaft Tagesmütter - Gen.Tscherms2017-10-05MRHMRA17R45F132NLAGEDER JOHANNALana/Lana2019-10-07...394.0010.0000.0404.0074802020-01-012020-12-31
9310Erklärung_Gemeinde_Völs am Schlern_2020.xlsxBAUMGARTNER PAUL //Sozialgenossenschaft Tagesmütter - Gen.Völs am Schlern2019-09-29BMGPLA19P29A952IHASELRIEDER ANGELIKAVöls am Schlern/Fie' allo Sciliar2020-12-21...13.500.0000.013.500002020-12-212020-12-31
9413Erklärung_Gemeinde_Völs am Schlern_2020.xlsxHOFER HANNAHSozialgenossenschaft Tagesmütter - Gen.Völs am Schlern2017-09-25HFRHNH17P65B160XHASELRIEDER ANGELIKAVöls am Schlern/Fie' allo Sciliar2018-04-23...335.25120.000-11.5443.7574002020-01-012020-09-18
9518Erklärung_Gemeinde_Welsberg_2020.xlsxMOSER ELIASSozialgenossenschaft Tagesmütter - Gen.Welsberg2018-08-18MSRLSE18M18B220WRAUTER INGEOlang/Valdaora2020-11-02...84.0016.0000.0100.000802020-11-022020-12-31
\n", + "

96 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 filename \\\n", + "0 11 Erklärung_Gemeinde_Algund_2020.xlsx \n", + "1 16 Erklärung_Gemeinde_Algund_2020.xlsx \n", + "2 8 Erklärung_Gemeinde_Branzoll_2020.xlsx \n", + "3 9 Erklärung_Gemeinde_Brixen_2020.xlsx \n", + "4 23 Erklärung_Gemeinde_Brixen_2020.xlsx \n", + ".. ... ... \n", + "91 10 Erklärung_Gemeinde_Terenten_2020.xlsx \n", + "92 8 Erklärung_Gemeinde_Tscherms_2020.xlsx \n", + "93 10 Erklärung_Gemeinde_Völs am Schlern_2020.xlsx \n", + "94 13 Erklärung_Gemeinde_Völs am Schlern_2020.xlsx \n", + "95 18 Erklärung_Gemeinde_Welsberg_2020.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "0 FLARER THEO Sozialgenossenschaft Tagesmütter - Gen. \n", + "1 MIRANDOLA LENZ Sozialgenossenschaft Tagesmütter - Gen. \n", + "2 CABULA LEONARDO Sozialgenossenschaft Tagesmütter - Gen. \n", + "3 ALBERTI VICKY Sozialgenossenschaft Tagesmütter - Gen. \n", + "4 NITZ MIA Sozialgenossenschaft Tagesmütter - Gen. \n", + ".. ... ... \n", + "91 INNERHOFER JULIAN Sozialgenossenschaft Tagesmütter - Gen. \n", + "92 MAIRHOFER MARIE Sozialgenossenschaft Tagesmütter - Gen. \n", + "93 BAUMGARTNER PAUL // Sozialgenossenschaft Tagesmütter - Gen. \n", + "94 HOFER HANNAH Sozialgenossenschaft Tagesmütter - Gen. \n", + "95 MOSER ELIAS Sozialgenossenschaft Tagesmütter - Gen. \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "0 Algund 2018-07-11 FLRTHE18L11F132U \n", + "1 Algund 2019-03-17 MRNLNZ19C17F132A \n", + "2 Branzoll 2017-07-24 CBLLRD17L24A952H \n", + "3 Brixen 2017-11-03 LBRVKY17S43B160U \n", + "4 Brixen 2017-10-06 NTZMIA17R46B160F \n", + ".. ... ... ... \n", + "91 Terenten 2017-01-17 NNRJLN17A17B220Y \n", + "92 Tscherms 2017-10-05 MRHMRA17R45F132N \n", + "93 Völs am Schlern 2019-09-29 BMGPLA19P29A952I \n", + "94 Völs am Schlern 2017-09-25 HFRHNH17P65B160X \n", + "95 Welsberg 2018-08-18 MSRLSE18M18B220W \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 LADURNER JOHANNA \n", + "1 BRUNELLO CHRISTINE \n", + "2 PUFF CHRISTINA \n", + "3 PUNER PAULA \n", + "4 PUNER PAULA \n", + ".. ... \n", + "91 LECHNER MARTHA \n", + "92 LAGEDER JOHANNA \n", + "93 HASELRIEDER ANGELIKA \n", + "94 HASELRIEDER ANGELIKA \n", + "95 RAUTER INGE \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 Meran/Merano \n", + "1 Algund/Lagundo \n", + "2 Leifers/Laives \n", + "3 Vahrn/Varna \n", + "4 Vahrn/Varna \n", + ".. ... \n", + "91 Terenten/Terento \n", + "92 Lana/Lana \n", + "93 Völs am Schlern/Fie' allo Sciliar \n", + "94 Völs am Schlern/Fie' allo Sciliar \n", + "95 Olang/Valdaora \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "0 2020-03-02 ... \n", + "1 2020-11-09 ... \n", + "2 2020-01-27 ... \n", + "3 2018-09-03 ... \n", + "4 2018-09-24 ... \n", + ".. ... ... \n", + "91 2018-01-08 ... \n", + "92 2019-10-07 ... \n", + "93 2020-12-21 ... \n", + "94 2018-04-23 ... \n", + "95 2020-11-02 ... \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 459.00 \n", + "1 74.50 \n", + "2 1199.50 \n", + "3 884.25 \n", + "4 868.50 \n", + ".. ... \n", + "91 208.00 \n", + "92 394.00 \n", + "93 13.50 \n", + "94 335.25 \n", + "95 84.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 337.00 \n", + "1 23.75 \n", + "2 348.00 \n", + "3 234.00 \n", + "4 296.00 \n", + ".. ... \n", + "91 406.00 \n", + "92 10.00 \n", + "93 0.00 \n", + "94 120.00 \n", + "95 16.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "91 0 \n", + "92 0 \n", + "93 0 \n", + "94 0 \n", + "95 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 0.5 \n", + "1 0.0 \n", + "2 4.0 \n", + "3 24.5 \n", + "4 29.0 \n", + ".. ... \n", + "91 0.0 \n", + "92 0.0 \n", + "93 0.0 \n", + "94 -11.5 \n", + "95 0.0 \n", + "\n", + " Ore totali rendicontate per il 2020 gg1 gg2 gg3 inizioNorm fineNorm \n", + "0 796.50 74 8 0 2020-03-02 2020-12-31 \n", + "1 98.25 0 8 0 2020-11-09 2020-12-31 \n", + "2 1551.50 74 8 2 2020-01-27 2020-12-31 \n", + "3 1142.75 74 8 0 2020-01-01 2020-12-31 \n", + "4 1193.50 74 8 0 2020-01-01 2020-12-31 \n", + ".. ... ... ... ... ... ... \n", + "91 614.00 74 0 0 2020-01-01 2020-06-26 \n", + "92 404.00 74 8 0 2020-01-01 2020-12-31 \n", + "93 13.50 0 0 0 2020-12-21 2020-12-31 \n", + "94 443.75 74 0 0 2020-01-01 2020-09-18 \n", + "95 100.00 0 8 0 2020-11-02 2020-12-31 \n", + "\n", + "[96 rows x 22 columns]" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "id": "efe7453b", + "metadata": {}, + "outputs": [], + "source": [ + "df1 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020'].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "id": "35f841b2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020
0Algund2
1Bozen14
2Branzoll1
3Brixen2
4Bruneck1
5Eppan a.d. Weinstr.3
6Freienfeld2
7Gargazon0
8Klausen0
9Laas1
10Lana8
11Leifers1
12Mals1
13Meran5
14Montan3
15Mölten0
16Nals1
17Natz-Schabs1
18Niederdorf2
19Pfalzen2
20Pfitsch3
21Plaus0
22Prad am Stilfser Joch1
23Rasen-Antholz4
24Ratschings2
25Ritten6
26Sarntal2
27Schenna0
28Schlanders2
29St.Lorenzen1
30St.Pankraz1
31Sterzing1
32Terenten1
33Tscherms1
34Völs am Schlern1
35Welsberg1
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \n", + "0 2 \n", + "1 14 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 8 \n", + "11 1 \n", + "12 1 \n", + "13 5 \n", + "14 3 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 0 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 6 \n", + "26 2 \n", + "27 0 \n", + "28 2 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 1 \n", + "35 1 " + ] + }, + "execution_count": 119, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "80383dd4", + "metadata": {}, + "outputs": [], + "source": [ + "df2 = df.groupby('Comune',as_index=False)['Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019'].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "id": "ec98651e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 117, + "id": "164407c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre di assistenza \\n ai sensi della delibera\\nn. 666/2019
0Algund2
1Bozen17
2Branzoll1
3Brixen2
4Bruneck2
5Eppan a.d. Weinstr.4
6Freienfeld2
7Gargazon1
8Klausen1
9Laas1
10Lana9
11Leifers2
12Mals2
13Meran5
14Montan3
15Mölten2
16Nals1
17Natz-Schabs1
18Niederdorf2
19Pfalzen2
20Pfitsch3
21Plaus1
22Prad am Stilfser Joch1
23Rasen-Antholz4
24Ratschings2
25Ritten7
26Sarntal2
27Schenna1
28Schlanders3
29St.Lorenzen1
30St.Pankraz1
31Sterzing1
32Terenten1
33Tscherms1
34Völs am Schlern2
35Welsberg1
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \n", + "0 2 \n", + "1 17 \n", + "2 1 \n", + "3 2 \n", + "4 2 \n", + "5 4 \n", + "6 2 \n", + "7 1 \n", + "8 1 \n", + "9 1 \n", + "10 9 \n", + "11 2 \n", + "12 2 \n", + "13 5 \n", + "14 3 \n", + "15 2 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 1 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 7 \n", + "26 2 \n", + "27 1 \n", + "28 3 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 2 \n", + "35 1 " + ] + }, + "execution_count": 117, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "id": "81ac6e1b", + "metadata": {}, + "outputs": [], + "source": [ + "df3 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020'].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "id": "517b1f4b", + "metadata": {}, + "outputs": [], + "source": [ + "df4 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)'].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "id": "20e20989", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)
0Algund1
1Bozen10
2Branzoll1
3Brixen2
4Bruneck1
5Eppan a.d. Weinstr.3
6Freienfeld2
7Gargazon0
8Klausen0
9Laas1
10Lana2
11Leifers1
12Mals0
13Meran4
14Montan2
15Mölten0
16Nals1
17Natz-Schabs1
18Niederdorf2
19Pfalzen2
20Pfitsch1
21Plaus0
22Prad am Stilfser Joch0
23Rasen-Antholz2
24Ratschings0
25Ritten4
26Sarntal0
27Schenna0
28Schlanders1
29St.Lorenzen1
30St.Pankraz0
31Sterzing0
32Terenten0
33Tscherms0
34Völs am Schlern0
35Welsberg0
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \n", + "0 1 \n", + "1 10 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 2 \n", + "11 1 \n", + "12 0 \n", + "13 4 \n", + "14 2 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 1 \n", + "21 0 \n", + "22 0 \n", + "23 2 \n", + "24 0 \n", + "25 4 \n", + "26 0 \n", + "27 0 \n", + "28 1 \n", + "29 1 \n", + "30 0 \n", + "31 0 \n", + "32 0 \n", + "33 0 \n", + "34 0 \n", + "35 0 " + ] + }, + "execution_count": 131, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df4" + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "id": "6edf0688", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = pd.merge(df1, df2, on='Comune', how='outer')" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "id": "f6dd4f5a", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = pd.merge(dfx, df3, on='Comune', how='outer')" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "id": "234745e0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020
0Algund220
1Bozen14170
2Branzoll110
3Brixen220
4Bruneck120
5Eppan a.d. Weinstr.340
6Freienfeld220
7Gargazon010
8Klausen010
9Laas110
10Lana890
11Leifers120
12Mals120
13Meran550
14Montan330
15Mölten020
16Nals110
17Natz-Schabs110
18Niederdorf220
19Pfalzen220
20Pfitsch330
21Plaus010
22Prad am Stilfser Joch110
23Rasen-Antholz440
24Ratschings220
25Ritten670
26Sarntal220
27Schenna010
28Schlanders230
29St.Lorenzen110
30St.Pankraz110
31Sterzing110
32Terenten110
33Tscherms110
34Völs am Schlern120
35Welsberg110
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 2 \n", + "1 14 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 8 \n", + "11 1 \n", + "12 1 \n", + "13 5 \n", + "14 3 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 0 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 6 \n", + "26 2 \n", + "27 0 \n", + "28 2 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 1 \n", + "35 1 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 2 \n", + "1 17 \n", + "2 1 \n", + "3 2 \n", + "4 2 \n", + "5 4 \n", + "6 2 \n", + "7 1 \n", + "8 1 \n", + "9 1 \n", + "10 9 \n", + "11 2 \n", + "12 2 \n", + "13 5 \n", + "14 3 \n", + "15 2 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 1 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 7 \n", + "26 2 \n", + "27 1 \n", + "28 3 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 2 \n", + "35 1 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + "5 0 \n", + "6 0 \n", + "7 0 \n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 0 \n", + "26 0 \n", + "27 0 \n", + "28 0 \n", + "29 0 \n", + "30 0 \n", + "31 0 \n", + "32 0 \n", + "33 0 \n", + "34 0 \n", + "35 0 " + ] + }, + "execution_count": 124, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "id": "29cdf3c9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0filenameCognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)...Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020gg1gg2gg3inizioNormfineNorm
011Erklärung_Gemeinde_Algund_2020.xlsxFLARER THEOSozialgenossenschaft Tagesmütter - Gen.Algund2018-07-11FLRTHE18L11F132ULADURNER JOHANNAMeran/Merano2020-03-02...459.00337.0000.5796.5074802020-03-022020-12-31
116Erklärung_Gemeinde_Algund_2020.xlsxMIRANDOLA LENZSozialgenossenschaft Tagesmütter - Gen.Algund2019-03-17MRNLNZ19C17F132ABRUNELLO CHRISTINEAlgund/Lagundo2020-11-09...74.5023.7500.098.250802020-11-092020-12-31
28Erklärung_Gemeinde_Branzoll_2020.xlsxCABULA LEONARDOSozialgenossenschaft Tagesmütter - Gen.Branzoll2017-07-24CBLLRD17L24A952HPUFF CHRISTINALeifers/Laives2020-01-27...1199.50348.0004.01551.5074822020-01-272020-12-31
39Erklärung_Gemeinde_Brixen_2020.xlsxALBERTI VICKYSozialgenossenschaft Tagesmütter - Gen.Brixen2017-11-03LBRVKY17S43B160UPUNER PAULAVahrn/Varna2018-09-03...884.25234.00024.51142.7574802020-01-012020-12-31
423Erklärung_Gemeinde_Brixen_2020.xlsxNITZ MIASozialgenossenschaft Tagesmütter - Gen.Brixen2017-10-06NTZMIA17R46B160FPUNER PAULAVahrn/Varna2018-09-24...868.50296.00029.01193.5074802020-01-012020-12-31
..................................................................
9110Erklärung_Gemeinde_Terenten_2020.xlsxINNERHOFER JULIANSozialgenossenschaft Tagesmütter - Gen.Terenten2017-01-17NNRJLN17A17B220YLECHNER MARTHATerenten/Terento2018-01-08...208.00406.0000.0614.0074002020-01-012020-06-26
928Erklärung_Gemeinde_Tscherms_2020.xlsxMAIRHOFER MARIESozialgenossenschaft Tagesmütter - Gen.Tscherms2017-10-05MRHMRA17R45F132NLAGEDER JOHANNALana/Lana2019-10-07...394.0010.0000.0404.0074802020-01-012020-12-31
9310Erklärung_Gemeinde_Völs am Schlern_2020.xlsxBAUMGARTNER PAUL //Sozialgenossenschaft Tagesmütter - Gen.Völs am Schlern2019-09-29BMGPLA19P29A952IHASELRIEDER ANGELIKAVöls am Schlern/Fie' allo Sciliar2020-12-21...13.500.0000.013.500002020-12-212020-12-31
9413Erklärung_Gemeinde_Völs am Schlern_2020.xlsxHOFER HANNAHSozialgenossenschaft Tagesmütter - Gen.Völs am Schlern2017-09-25HFRHNH17P65B160XHASELRIEDER ANGELIKAVöls am Schlern/Fie' allo Sciliar2018-04-23...335.25120.000-11.5443.7574002020-01-012020-09-18
9518Erklärung_Gemeinde_Welsberg_2020.xlsxMOSER ELIASSozialgenossenschaft Tagesmütter - Gen.Welsberg2018-08-18MSRLSE18M18B220WRAUTER INGEOlang/Valdaora2020-11-02...84.0016.0000.0100.000802020-11-022020-12-31
\n", + "

96 rows × 22 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 filename \\\n", + "0 11 Erklärung_Gemeinde_Algund_2020.xlsx \n", + "1 16 Erklärung_Gemeinde_Algund_2020.xlsx \n", + "2 8 Erklärung_Gemeinde_Branzoll_2020.xlsx \n", + "3 9 Erklärung_Gemeinde_Brixen_2020.xlsx \n", + "4 23 Erklärung_Gemeinde_Brixen_2020.xlsx \n", + ".. ... ... \n", + "91 10 Erklärung_Gemeinde_Terenten_2020.xlsx \n", + "92 8 Erklärung_Gemeinde_Tscherms_2020.xlsx \n", + "93 10 Erklärung_Gemeinde_Völs am Schlern_2020.xlsx \n", + "94 13 Erklärung_Gemeinde_Völs am Schlern_2020.xlsx \n", + "95 18 Erklärung_Gemeinde_Welsberg_2020.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "0 FLARER THEO Sozialgenossenschaft Tagesmütter - Gen. \n", + "1 MIRANDOLA LENZ Sozialgenossenschaft Tagesmütter - Gen. \n", + "2 CABULA LEONARDO Sozialgenossenschaft Tagesmütter - Gen. \n", + "3 ALBERTI VICKY Sozialgenossenschaft Tagesmütter - Gen. \n", + "4 NITZ MIA Sozialgenossenschaft Tagesmütter - Gen. \n", + ".. ... ... \n", + "91 INNERHOFER JULIAN Sozialgenossenschaft Tagesmütter - Gen. \n", + "92 MAIRHOFER MARIE Sozialgenossenschaft Tagesmütter - Gen. \n", + "93 BAUMGARTNER PAUL // Sozialgenossenschaft Tagesmütter - Gen. \n", + "94 HOFER HANNAH Sozialgenossenschaft Tagesmütter - Gen. \n", + "95 MOSER ELIAS Sozialgenossenschaft Tagesmütter - Gen. \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "0 Algund 2018-07-11 FLRTHE18L11F132U \n", + "1 Algund 2019-03-17 MRNLNZ19C17F132A \n", + "2 Branzoll 2017-07-24 CBLLRD17L24A952H \n", + "3 Brixen 2017-11-03 LBRVKY17S43B160U \n", + "4 Brixen 2017-10-06 NTZMIA17R46B160F \n", + ".. ... ... ... \n", + "91 Terenten 2017-01-17 NNRJLN17A17B220Y \n", + "92 Tscherms 2017-10-05 MRHMRA17R45F132N \n", + "93 Völs am Schlern 2019-09-29 BMGPLA19P29A952I \n", + "94 Völs am Schlern 2017-09-25 HFRHNH17P65B160X \n", + "95 Welsberg 2018-08-18 MSRLSE18M18B220W \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 LADURNER JOHANNA \n", + "1 BRUNELLO CHRISTINE \n", + "2 PUFF CHRISTINA \n", + "3 PUNER PAULA \n", + "4 PUNER PAULA \n", + ".. ... \n", + "91 LECHNER MARTHA \n", + "92 LAGEDER JOHANNA \n", + "93 HASELRIEDER ANGELIKA \n", + "94 HASELRIEDER ANGELIKA \n", + "95 RAUTER INGE \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 Meran/Merano \n", + "1 Algund/Lagundo \n", + "2 Leifers/Laives \n", + "3 Vahrn/Varna \n", + "4 Vahrn/Varna \n", + ".. ... \n", + "91 Terenten/Terento \n", + "92 Lana/Lana \n", + "93 Völs am Schlern/Fie' allo Sciliar \n", + "94 Völs am Schlern/Fie' allo Sciliar \n", + "95 Olang/Valdaora \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "0 2020-03-02 ... \n", + "1 2020-11-09 ... \n", + "2 2020-01-27 ... \n", + "3 2018-09-03 ... \n", + "4 2018-09-24 ... \n", + ".. ... ... \n", + "91 2018-01-08 ... \n", + "92 2019-10-07 ... \n", + "93 2020-12-21 ... \n", + "94 2018-04-23 ... \n", + "95 2020-11-02 ... \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 459.00 \n", + "1 74.50 \n", + "2 1199.50 \n", + "3 884.25 \n", + "4 868.50 \n", + ".. ... \n", + "91 208.00 \n", + "92 394.00 \n", + "93 13.50 \n", + "94 335.25 \n", + "95 84.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 337.00 \n", + "1 23.75 \n", + "2 348.00 \n", + "3 234.00 \n", + "4 296.00 \n", + ".. ... \n", + "91 406.00 \n", + "92 10.00 \n", + "93 0.00 \n", + "94 120.00 \n", + "95 16.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "91 0 \n", + "92 0 \n", + "93 0 \n", + "94 0 \n", + "95 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 0.5 \n", + "1 0.0 \n", + "2 4.0 \n", + "3 24.5 \n", + "4 29.0 \n", + ".. ... \n", + "91 0.0 \n", + "92 0.0 \n", + "93 0.0 \n", + "94 -11.5 \n", + "95 0.0 \n", + "\n", + " Ore totali rendicontate per il 2020 gg1 gg2 gg3 inizioNorm fineNorm \n", + "0 796.50 74 8 0 2020-03-02 2020-12-31 \n", + "1 98.25 0 8 0 2020-11-09 2020-12-31 \n", + "2 1551.50 74 8 2 2020-01-27 2020-12-31 \n", + "3 1142.75 74 8 0 2020-01-01 2020-12-31 \n", + "4 1193.50 74 8 0 2020-01-01 2020-12-31 \n", + ".. ... ... ... ... ... ... \n", + "91 614.00 74 0 0 2020-01-01 2020-06-26 \n", + "92 404.00 74 8 0 2020-01-01 2020-12-31 \n", + "93 13.50 0 0 0 2020-12-21 2020-12-31 \n", + "94 443.75 74 0 0 2020-01-01 2020-09-18 \n", + "95 100.00 0 8 0 2020-11-02 2020-12-31 \n", + "\n", + "[96 rows x 22 columns]" + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "id": "ea29e314", + "metadata": {}, + "outputs": [], + "source": [ + "df4 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)'].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "id": "0353e738", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)
0Algund1
1Bozen10
2Branzoll1
3Brixen2
4Bruneck1
5Eppan a.d. Weinstr.3
6Freienfeld2
7Gargazon0
8Klausen0
9Laas1
10Lana2
11Leifers1
12Mals0
13Meran4
14Montan2
15Mölten0
16Nals1
17Natz-Schabs1
18Niederdorf2
19Pfalzen2
20Pfitsch1
21Plaus0
22Prad am Stilfser Joch0
23Rasen-Antholz2
24Ratschings0
25Ritten4
26Sarntal0
27Schenna0
28Schlanders1
29St.Lorenzen1
30St.Pankraz0
31Sterzing0
32Terenten0
33Tscherms0
34Völs am Schlern0
35Welsberg0
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \n", + "0 1 \n", + "1 10 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 2 \n", + "11 1 \n", + "12 0 \n", + "13 4 \n", + "14 2 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 1 \n", + "21 0 \n", + "22 0 \n", + "23 2 \n", + "24 0 \n", + "25 4 \n", + "26 0 \n", + "27 0 \n", + "28 1 \n", + "29 1 \n", + "30 0 \n", + "31 0 \n", + "32 0 \n", + "33 0 \n", + "34 0 \n", + "35 0 " + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df4" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "id": "be3f80d6", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = pd.merge(dfx, df4, on='Comune', how='outer')" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "id": "82d11873", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)
0Algund2201
1Bozen1417010
2Branzoll1101
3Brixen2202
4Bruneck1201
5Eppan a.d. Weinstr.3403
6Freienfeld2202
7Gargazon0100
8Klausen0100
9Laas1101
10Lana8902
11Leifers1201
12Mals1200
13Meran5504
14Montan3302
15Mölten0200
16Nals1101
17Natz-Schabs1101
18Niederdorf2202
19Pfalzen2202
20Pfitsch3301
21Plaus0100
22Prad am Stilfser Joch1100
23Rasen-Antholz4402
24Ratschings2200
25Ritten6704
26Sarntal2200
27Schenna0100
28Schlanders2301
29St.Lorenzen1101
30St.Pankraz1100
31Sterzing1100
32Terenten1100
33Tscherms1100
34Völs am Schlern1200
35Welsberg1100
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Algund \n", + "1 Bozen \n", + "2 Branzoll \n", + "3 Brixen \n", + "4 Bruneck \n", + "5 Eppan a.d. Weinstr. \n", + "6 Freienfeld \n", + "7 Gargazon \n", + "8 Klausen \n", + "9 Laas \n", + "10 Lana \n", + "11 Leifers \n", + "12 Mals \n", + "13 Meran \n", + "14 Montan \n", + "15 Mölten \n", + "16 Nals \n", + "17 Natz-Schabs \n", + "18 Niederdorf \n", + "19 Pfalzen \n", + "20 Pfitsch \n", + "21 Plaus \n", + "22 Prad am Stilfser Joch \n", + "23 Rasen-Antholz \n", + "24 Ratschings \n", + "25 Ritten \n", + "26 Sarntal \n", + "27 Schenna \n", + "28 Schlanders \n", + "29 St.Lorenzen \n", + "30 St.Pankraz \n", + "31 Sterzing \n", + "32 Terenten \n", + "33 Tscherms \n", + "34 Völs am Schlern \n", + "35 Welsberg \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 2 \n", + "1 14 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 8 \n", + "11 1 \n", + "12 1 \n", + "13 5 \n", + "14 3 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 0 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 6 \n", + "26 2 \n", + "27 0 \n", + "28 2 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 1 \n", + "35 1 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 2 \n", + "1 17 \n", + "2 1 \n", + "3 2 \n", + "4 2 \n", + "5 4 \n", + "6 2 \n", + "7 1 \n", + "8 1 \n", + "9 1 \n", + "10 9 \n", + "11 2 \n", + "12 2 \n", + "13 5 \n", + "14 3 \n", + "15 2 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 3 \n", + "21 1 \n", + "22 1 \n", + "23 4 \n", + "24 2 \n", + "25 7 \n", + "26 2 \n", + "27 1 \n", + "28 3 \n", + "29 1 \n", + "30 1 \n", + "31 1 \n", + "32 1 \n", + "33 1 \n", + "34 2 \n", + "35 1 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + "5 0 \n", + "6 0 \n", + "7 0 \n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "25 0 \n", + "26 0 \n", + "27 0 \n", + "28 0 \n", + "29 0 \n", + "30 0 \n", + "31 0 \n", + "32 0 \n", + "33 0 \n", + "34 0 \n", + "35 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \n", + "0 1 \n", + "1 10 \n", + "2 1 \n", + "3 2 \n", + "4 1 \n", + "5 3 \n", + "6 2 \n", + "7 0 \n", + "8 0 \n", + "9 1 \n", + "10 2 \n", + "11 1 \n", + "12 0 \n", + "13 4 \n", + "14 2 \n", + "15 0 \n", + "16 1 \n", + "17 1 \n", + "18 2 \n", + "19 2 \n", + "20 1 \n", + "21 0 \n", + "22 0 \n", + "23 2 \n", + "24 0 \n", + "25 4 \n", + "26 0 \n", + "27 0 \n", + "28 1 \n", + "29 1 \n", + "30 0 \n", + "31 0 \n", + "32 0 \n", + "33 0 \n", + "34 0 \n", + "35 0 " + ] + }, + "execution_count": 129, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b51fcfb7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git "a/pages/Jupyter/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" "b/pages/Jupyter/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..91310e5cf885724a3696b025cdebb8e7037cab30 Binary files /dev/null and "b/pages/Jupyter/Erkla\314\210rung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx" differ diff --git a/pages/Jupyter/ErroreOreMaxProportion.ipynb b/pages/Jupyter/ErroreOreMaxProportion.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..eefb371d386315017358eec13984c743bc48dff2 --- /dev/null +++ b/pages/Jupyter/ErroreOreMaxProportion.ipynb @@ -0,0 +1,4011 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"Erklärung Gemeinden Jahr 2020 Tramin.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f5ad0313", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Tramin'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger = traeger[3].title()\n", + "gemeinde = df.iloc[3]\n", + "gemeinde = gemeinde[3]\n", + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)\n", + "cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + "df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + "df.loc[cond, \"Cognome e nome bambino\"] += \" *\"\n", + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")\n", + "validi = df[\"Numero \\nprogressivo\"].notna()\n", + "df = df[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + "condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + ")\n", + "anno_riferimento = 2020\n", + "df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + "] = \"12-31-\" + str(anno_riferimento)\n", + "\n", + "anno_riferimento = 2020\n", + "df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + "] = \"12-31-\" + str(anno_riferimento)\n", + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")\n", + "\n", + "df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + "].astype(\"datetime64[ns]\")\n", + "\n", + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + "].astype(\"datetime64[ns]\")\n", + "\n", + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")\n", + "\n", + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)\n", + "\n", + "df.insert(1, \"Comune\", gemeinde)\n", + "df.insert(1, \"Ente\", traeger)\n", + "df = df.fillna(0)\n", + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()\n", + "\n", + "ar = 2020\n", + "\n", + "df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + "]\n", + "\n", + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + "\n", + "iniz = df[\"inizioNorm\"].dt.year < ar\n", + "\n", + "df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + ") \n", + "\n", + "fin = df[\"fineNorm\"].dt.year > ar\n", + "\n", + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)\n", + "\n", + "df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + ") \n", + "\n", + "df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + ").dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "af6a6cf6", + "metadata": {}, + "outputs": [], + "source": [ + "condizioneerrore = ((1920 * (df[\"GiorniAssistenzaAnnoRiferimento\"])) / 366) < df[\n", + " \"Ore totali rendicontate per il 2020\"\n", + "]\n", + " \n", + "condizioneerrore2 = ((1920 * (df.groupby(\"Codice fiscale\")[\"GiorniAssistenzaAnnoRiferimento\"].transform(\"sum\")) / 366)) < df.groupby(\"Codice fiscale\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "08e4a7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "KJNMIA18M43A952A\n", + "KJNMIA18M43A952A\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "VNCDLN19B19A952G\n", + "VNCDLN19B19A952G\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n" + ] + } + ], + "source": [ + "for i in df[~codfisc1][\"Codice fiscale\"]:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "29ed03dd", + "metadata": {}, + "outputs": [], + "source": [ + "codfisc1 = df.groupby(\"Codice fiscale\")[\"Codice fiscale\"].transform(\"count\") == 1" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "d9f22c6d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-27326.500.0000.026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-06126189.75270.500332.5792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-31165804.0010.2500.0814.252020-07-202020-12-31
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "12 12 \n", + "13 3 \n", + "14 126 \n", + "15 165 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "12 0.0 \n", + "13 0.0 \n", + "14 332.5 \n", + "15 0.0 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[condizioneerrore2 & ~codfisc1]" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "8077a967", + "metadata": {}, + "outputs": [], + "source": [ + "ll = [\"Eppan\",\"Bozen\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "7285e8fd", + "metadata": {}, + "outputs": [], + "source": [ + "ddff = df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.contains(\"Epp\") | df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.contains(\"Boz\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "14e0625c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-313661308.7589.500-340.001058.252020-01-012020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-0412599.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.0071.502020-08-172020-08-28
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-23127231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-06127173.50279.500364.50817.502020-01-012020-05-06
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-0418.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-2117.000.0000.007.002020-08-212020-08-21
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-183274.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "11 Eppan \n", + "12 Eppan \n", + "16 Eppan \n", + "17 Eppan \n", + "21 Eppan \n", + "22 Eppan \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 366 \n", + "11 125 \n", + "12 12 \n", + "16 127 \n", + "17 127 \n", + "21 1 \n", + "22 1 \n", + "24 32 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "11 99.50 \n", + "12 71.50 \n", + "16 231.50 \n", + "17 173.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "11 144.75 \n", + "12 0.00 \n", + "16 20.75 \n", + "17 279.50 \n", + "21 0.00 \n", + "22 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "11 0 \n", + "12 0 \n", + "16 0 \n", + "17 0 \n", + "21 0 \n", + "22 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "11 66.25 \n", + "12 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "21 0.00 \n", + "22 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[ddff]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "2863d5d8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 Bozen\n", + "9 Kurtatsch\n", + "10 Kaltern\n", + "11 Eppan\n", + "12 Eppan\n", + "13 Margreid\n", + "14 Kurtatsch\n", + "15 Kurtatsch\n", + "16 Eppan\n", + "17 Eppan\n", + "18 Margreid\n", + "19 Kurtatsch\n", + "20 Margreid\n", + "21 Eppan\n", + "22 Eppan\n", + "23 Margreid\n", + "24 Eppan\n", + "Name: Comune di residenza assistente domiciliare all'infanzia, dtype: object" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Comune di residenza assistente domiciliare all'infanzia\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "2bb0df6d", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "cannot insert massimo543, already exists", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [55]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minsert\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m12\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmassimo543\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/frame.py:4414\u001b[0m, in \u001b[0;36mDataFrame.insert\u001b[0;34m(self, loc, column, value, allow_duplicates)\u001b[0m\n\u001b[1;32m 4408\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 4409\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCannot specify \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mallow_duplicates=True\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m when \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 4410\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mself.flags.allows_duplicate_labels\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m is False.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 4411\u001b[0m )\n\u001b[1;32m 4412\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m allow_duplicates \u001b[38;5;129;01mand\u001b[39;00m column \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns:\n\u001b[1;32m 4413\u001b[0m \u001b[38;5;66;03m# Should this be a different kind of error??\u001b[39;00m\n\u001b[0;32m-> 4414\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcannot insert \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mcolumn\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m, already exists\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 4415\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(loc, \u001b[38;5;28mint\u001b[39m):\n\u001b[1;32m 4416\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mloc must be int\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mValueError\u001b[0m: cannot insert massimo543, already exists" + ] + } + ], + "source": [ + "df.insert(12,\"massimo543\",0)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "e9c25c84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentomassimo543Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-3136601308.7589.500-340.001058.252020-01-012020-12-31
9Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-102020-05-055700.0090.0000.0090.002020-03-102020-05-05
10Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-182020-12-312280559.5024.000-1.75581.752020-05-182020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-04125099.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-2812071.500.0000.0071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-273026.500.0000.0026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-061260189.75270.500332.50792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-311650804.0010.2500.00814.252020-07-202020-12-31
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-231270231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-061270173.50279.500364.50817.502020-01-012020-05-06
18Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-062020-12-311790390.7520.0000.00410.752020-07-062020-12-31
19Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-032020-05-0694055.00120.00050.00225.002020-02-032020-05-06
20Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-072020-02-08204.500.0000.004.502020-02-072020-02-08
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-04108.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-21107.000.0000.007.002020-08-212020-08-21
23Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-022020-03-043015.000.0000.0015.002020-03-022020-03-04
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-1832074.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "18 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "19 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "20 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "23 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "9 Tramin 2018-05-29 FREJRU18E29A952R \n", + "10 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "18 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "19 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "20 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "23 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "9 2020-03-10 \n", + "10 2020-05-18 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "18 2020-07-06 \n", + "19 2020-02-03 \n", + "20 2020-02-07 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-02 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "9 2020-05-05 \n", + "10 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "18 2020-12-31 \n", + "19 2020-05-06 \n", + "20 2020-02-08 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-04 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento massimo543 \\\n", + "8 366 0 \n", + "9 57 0 \n", + "10 228 0 \n", + "11 125 0 \n", + "12 12 0 \n", + "13 3 0 \n", + "14 126 0 \n", + "15 165 0 \n", + "16 127 0 \n", + "17 127 0 \n", + "18 179 0 \n", + "19 94 0 \n", + "20 2 0 \n", + "21 1 0 \n", + "22 1 0 \n", + "23 3 0 \n", + "24 32 0 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "9 0.00 \n", + "10 559.50 \n", + "11 99.50 \n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "16 231.50 \n", + "17 173.50 \n", + "18 390.75 \n", + "19 55.00 \n", + "20 4.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "23 15.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "9 90.00 \n", + "10 24.00 \n", + "11 144.75 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.50 \n", + "18 20.00 \n", + "19 120.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "9 0.00 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 332.50 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "18 0.00 \n", + "19 50.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "9 90.00 2020-03-10 2020-05-05 \n", + "10 581.75 2020-05-18 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "18 410.75 2020-07-06 2020-12-31 \n", + "19 225.00 2020-02-03 2020-05-06 \n", + "20 4.50 2020-02-07 2020-02-08 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "23 15.00 2020-03-02 2020-03-04 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "f0431d5b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Cognome e nome bambino', 'Ente', 'Comune', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'GiorniAssistenzaAnnoRiferimento', 'massimo543',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'inizioNorm', 'fineNorm'],\n", + " dtype='object')" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "b9a017f4", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"pippo\"]= 0" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "4c8d31c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Cognome e nome bambino', 'Ente', 'Comune', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'GiorniAssistenzaAnnoRiferimento', 'massimo543',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'inizioNorm', 'fineNorm',\n", + " 'pippo'],\n", + " dtype='object')" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "3847bfe8", + "metadata": {}, + "outputs": [], + "source": [ + " cond1 = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ] <= pd.to_datetime(\"05.03.2020\", format=\"%d.%m.%Y\")\n", + " cond1b = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] > pd.to_datetime(\"17.05.2020\", format=\"%d.%m.%Y\")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "d35a3985", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[cond1 & cond1b,\"pippo\"] = 99" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "ea98ee38", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentomassimo543Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNormpippo
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-3136601308.7589.50-340.01058.252020-01-012020-12-3199
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento massimo543 \\\n", + "8 366 0 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.5 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.0 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm pippo \n", + "8 1058.25 2020-01-01 2020-12-31 99 " + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[cond1 & cond1b]" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "id": "18787244", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8 True\n", + "9 False\n", + "10 False\n", + "11 False\n", + "12 False\n", + "13 False\n", + "14 False\n", + "15 False\n", + "16 False\n", + "17 False\n", + "18 False\n", + "19 False\n", + "20 False\n", + "21 False\n", + "22 False\n", + "23 False\n", + "24 False\n", + "Name: Comune di residenza assistente domiciliare all'infanzia, dtype: bool" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains(\"bozen\")" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "0ff67d85", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'NoneType' object has no attribute 'astype'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [100]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minsert\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m13\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmassimo545\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mastype\u001b[49m(\u001b[38;5;28mint\u001b[39m)\n", + "\u001b[0;31mAttributeError\u001b[0m: 'NoneType' object has no attribute 'astype'" + ] + } + ], + "source": [ + "df.insert(13, \"massimo545\", 0).astype(int)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "06e28685", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
8Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-192020-12-313661308.7589.500-340.001058.252020-01-012020-12-31
9Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-102020-05-05570.0090.0000.0090.002020-03-102020-05-05
10Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-182020-12-31228559.5024.000-1.75581.752020-05-182020-12-31
11Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-062020-05-0412599.50144.75066.25310.502020-01-012020-05-04
12Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-172020-08-281271.500.0000.0071.502020-08-172020-08-28
13Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-252020-11-27326.500.0000.0026.502020-11-252020-11-27
14Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-022020-05-06126189.75270.500332.50792.752020-01-022020-05-06
15Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-202020-12-31165804.0010.2500.00814.252020-07-202020-12-31
16Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-202020-11-23127231.5020.7500.00252.252020-07-202020-11-23
17Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-252020-05-06127173.50279.500364.50817.502020-01-012020-05-06
18Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-062020-12-31179390.7520.0000.00410.752020-07-062020-12-31
19Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-032020-05-069455.00120.00050.00225.002020-02-032020-05-06
20Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-072020-02-0824.500.0000.004.502020-02-072020-02-08
21Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-042020-09-0418.000.0000.008.002020-09-042020-09-04
22Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-212020-08-2117.000.0000.007.002020-08-212020-08-21
23Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-022020-03-04315.000.0000.0015.002020-03-022020-03-04
24Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-182020-06-183274.750.0000.0074.752020-05-182020-06-18
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "8 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "18 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "19 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "20 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "21 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "22 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "23 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "24 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "8 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "9 Tramin 2018-05-29 FREJRU18E29A952R \n", + "10 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "11 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "12 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "13 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "14 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "15 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "16 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "17 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "18 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "19 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "20 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "21 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "22 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "23 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "24 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "8 Salvadori Paola \n", + "9 Peer Petra \n", + "10 Scarduelli Sonia \n", + "11 Ambach Maria \n", + "12 Ambach Maria \n", + "13 Huber Melanie \n", + "14 Peer Petra \n", + "15 Peer Petra \n", + "16 Ambach Maria \n", + "17 Ambach Maria \n", + "18 Huber Melanie \n", + "19 Peer Petra \n", + "20 Huber Melanie \n", + "21 Ambach Maria \n", + "22 Ambach Maria \n", + "23 Huber Melanie \n", + "24 Ambach Maria \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 Bozen \n", + "9 Kurtatsch \n", + "10 Kaltern \n", + "11 Eppan \n", + "12 Eppan \n", + "13 Margreid \n", + "14 Kurtatsch \n", + "15 Kurtatsch \n", + "16 Eppan \n", + "17 Eppan \n", + "18 Margreid \n", + "19 Kurtatsch \n", + "20 Margreid \n", + "21 Eppan \n", + "22 Eppan \n", + "23 Margreid \n", + "24 Eppan \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2019-11-19 \n", + "9 2020-03-10 \n", + "10 2020-05-18 \n", + "11 2019-08-06 \n", + "12 2020-08-17 \n", + "13 2020-11-25 \n", + "14 2020-01-02 \n", + "15 2020-07-20 \n", + "16 2020-07-20 \n", + "17 2019-11-25 \n", + "18 2020-07-06 \n", + "19 2020-02-03 \n", + "20 2020-02-07 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-02 \n", + "24 2020-05-18 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-12-31 \n", + "9 2020-05-05 \n", + "10 2020-12-31 \n", + "11 2020-05-04 \n", + "12 2020-08-28 \n", + "13 2020-11-27 \n", + "14 2020-05-06 \n", + "15 2020-12-31 \n", + "16 2020-11-23 \n", + "17 2020-05-06 \n", + "18 2020-12-31 \n", + "19 2020-05-06 \n", + "20 2020-02-08 \n", + "21 2020-09-04 \n", + "22 2020-08-21 \n", + "23 2020-03-04 \n", + "24 2020-06-18 \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "8 366 \n", + "9 57 \n", + "10 228 \n", + "11 125 \n", + "12 12 \n", + "13 3 \n", + "14 126 \n", + "15 165 \n", + "16 127 \n", + "17 127 \n", + "18 179 \n", + "19 94 \n", + "20 2 \n", + "21 1 \n", + "22 1 \n", + "23 3 \n", + "24 32 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 1308.75 \n", + "9 0.00 \n", + "10 559.50 \n", + "11 99.50 \n", + "12 71.50 \n", + "13 26.50 \n", + "14 189.75 \n", + "15 804.00 \n", + "16 231.50 \n", + "17 173.50 \n", + "18 390.75 \n", + "19 55.00 \n", + "20 4.50 \n", + "21 8.00 \n", + "22 7.00 \n", + "23 15.00 \n", + "24 74.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 89.50 \n", + "9 90.00 \n", + "10 24.00 \n", + "11 144.75 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 270.50 \n", + "15 10.25 \n", + "16 20.75 \n", + "17 279.50 \n", + "18 20.00 \n", + "19 120.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 0 \n", + "9 0 \n", + "10 0 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 0 \n", + "16 0 \n", + "17 0 \n", + "18 0 \n", + "19 0 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 0 \n", + "24 0 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 -340.00 \n", + "9 0.00 \n", + "10 -1.75 \n", + "11 66.25 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 332.50 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 364.50 \n", + "18 0.00 \n", + "19 50.00 \n", + "20 0.00 \n", + "21 0.00 \n", + "22 0.00 \n", + "23 0.00 \n", + "24 0.00 \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "8 1058.25 2020-01-01 2020-12-31 \n", + "9 90.00 2020-03-10 2020-05-05 \n", + "10 581.75 2020-05-18 2020-12-31 \n", + "11 310.50 2020-01-01 2020-05-04 \n", + "12 71.50 2020-08-17 2020-08-28 \n", + "13 26.50 2020-11-25 2020-11-27 \n", + "14 792.75 2020-01-02 2020-05-06 \n", + "15 814.25 2020-07-20 2020-12-31 \n", + "16 252.25 2020-07-20 2020-11-23 \n", + "17 817.50 2020-01-01 2020-05-06 \n", + "18 410.75 2020-07-06 2020-12-31 \n", + "19 225.00 2020-02-03 2020-05-06 \n", + "20 4.50 2020-02-07 2020-02-08 \n", + "21 8.00 2020-09-04 2020-09-04 \n", + "22 7.00 2020-08-21 2020-08-21 \n", + "23 15.00 2020-03-02 2020-03-04 \n", + "24 74.75 2020-05-18 2020-06-18 " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0e0e9be0", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'datetime' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [14]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdatetime\u001b[49m()\n", + "\u001b[0;31mNameError\u001b[0m: name 'datetime' is not defined" + ] + } + ], + "source": [ + "datetime()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e33c352e", + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import date" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "2f538193", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'10/06/2022'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "date.today().strftime(\"%d/%m/%Y\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "9e720f94", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.append({\"Comune di residenza assistente domiciliare all'infanzia\":\"file creato il\",\"Data inizio contratto (o data inizio assistenza se diversa)\":date.today().strftime(\"%d/%m/%Y\")}, ignore_index=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "f754d20c", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.append({}, ignore_index=True )" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "8db52565", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
0Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-19 00:00:002020-12-31366.01308.7589.500.0-340.001058.252020-01-012020-12-31
1Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-10 00:00:002020-05-0557.00.0090.000.00.0090.002020-03-102020-05-05
2Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-18 00:00:002020-12-31228.0559.5024.000.0-1.75581.752020-05-182020-12-31
3Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-06 00:00:002020-05-04125.099.50144.750.066.25310.502020-01-012020-05-04
4Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-17 00:00:002020-08-2812.071.500.000.00.0071.502020-08-172020-08-28
5Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-25 00:00:002020-11-273.026.500.000.00.0026.502020-11-252020-11-27
6Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-02 00:00:002020-05-06126.0189.75270.500.0332.50792.752020-01-022020-05-06
7Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-20 00:00:002020-12-31165.0804.0010.250.00.00814.252020-07-202020-12-31
8Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-20 00:00:002020-11-23127.0231.5020.750.00.00252.252020-07-202020-11-23
9Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-25 00:00:002020-05-06127.0173.50279.500.0364.50817.502020-01-012020-05-06
10Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-06 00:00:002020-12-31179.0390.7520.000.00.00410.752020-07-062020-12-31
11Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-03 00:00:002020-05-0694.055.00120.000.050.00225.002020-02-032020-05-06
12Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-07 00:00:002020-02-082.04.500.000.00.004.502020-02-072020-02-08
13Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-04 00:00:002020-09-041.08.000.000.00.008.002020-09-042020-09-04
14Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-21 00:00:002020-08-211.07.000.000.00.007.002020-08-212020-08-21
15Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-02 00:00:002020-03-043.015.000.000.00.0015.002020-03-022020-03-04
16Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-18 00:00:002020-06-1832.074.750.000.00.0074.752020-05-182020-06-18
17NaNNaNNaNNaTNaNNaNNaN10/06/2022NaTNaNNaNNaNNaNNaNNaNNaTNaT
18NaNNaNNaNNaTNaNNaNfile creato il10/06/2022NaTNaNNaNNaNNaNNaNNaNNaTNaT
19NaNNaNNaNNaTNaNNaNNaNNaNNaTNaNNaNNaNNaNNaNNaNNaTNaT
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "0 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "1 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "2 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "3 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "4 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "5 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "6 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "7 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "8 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 NaN NaN \n", + "18 NaN NaN \n", + "19 NaN NaN \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "0 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "1 Tramin 2018-05-29 FREJRU18E29A952R \n", + "2 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "3 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "4 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "5 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "6 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "7 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "8 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "9 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "10 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "11 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "12 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "13 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "14 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "15 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "16 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "17 NaN NaT NaN \n", + "18 NaN NaT NaN \n", + "19 NaN NaT NaN \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 Salvadori Paola \n", + "1 Peer Petra \n", + "2 Scarduelli Sonia \n", + "3 Ambach Maria \n", + "4 Ambach Maria \n", + "5 Huber Melanie \n", + "6 Peer Petra \n", + "7 Peer Petra \n", + "8 Ambach Maria \n", + "9 Ambach Maria \n", + "10 Huber Melanie \n", + "11 Peer Petra \n", + "12 Huber Melanie \n", + "13 Ambach Maria \n", + "14 Ambach Maria \n", + "15 Huber Melanie \n", + "16 Ambach Maria \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 Bozen \n", + "1 Kurtatsch \n", + "2 Kaltern \n", + "3 Eppan \n", + "4 Eppan \n", + "5 Margreid \n", + "6 Kurtatsch \n", + "7 Kurtatsch \n", + "8 Eppan \n", + "9 Eppan \n", + "10 Margreid \n", + "11 Kurtatsch \n", + "12 Margreid \n", + "13 Eppan \n", + "14 Eppan \n", + "15 Margreid \n", + "16 Eppan \n", + "17 NaN \n", + "18 file creato il \n", + "19 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 2019-11-19 00:00:00 \n", + "1 2020-03-10 00:00:00 \n", + "2 2020-05-18 00:00:00 \n", + "3 2019-08-06 00:00:00 \n", + "4 2020-08-17 00:00:00 \n", + "5 2020-11-25 00:00:00 \n", + "6 2020-01-02 00:00:00 \n", + "7 2020-07-20 00:00:00 \n", + "8 2020-07-20 00:00:00 \n", + "9 2019-11-25 00:00:00 \n", + "10 2020-07-06 00:00:00 \n", + "11 2020-02-03 00:00:00 \n", + "12 2020-02-07 00:00:00 \n", + "13 2020-09-04 00:00:00 \n", + "14 2020-08-21 00:00:00 \n", + "15 2020-03-02 00:00:00 \n", + "16 2020-05-18 00:00:00 \n", + "17 10/06/2022 \n", + "18 10/06/2022 \n", + "19 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 2020-12-31 \n", + "1 2020-05-05 \n", + "2 2020-12-31 \n", + "3 2020-05-04 \n", + "4 2020-08-28 \n", + "5 2020-11-27 \n", + "6 2020-05-06 \n", + "7 2020-12-31 \n", + "8 2020-11-23 \n", + "9 2020-05-06 \n", + "10 2020-12-31 \n", + "11 2020-05-06 \n", + "12 2020-02-08 \n", + "13 2020-09-04 \n", + "14 2020-08-21 \n", + "15 2020-03-04 \n", + "16 2020-06-18 \n", + "17 NaT \n", + "18 NaT \n", + "19 NaT \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "0 366.0 \n", + "1 57.0 \n", + "2 228.0 \n", + "3 125.0 \n", + "4 12.0 \n", + "5 3.0 \n", + "6 126.0 \n", + "7 165.0 \n", + "8 127.0 \n", + "9 127.0 \n", + "10 179.0 \n", + "11 94.0 \n", + "12 2.0 \n", + "13 1.0 \n", + "14 1.0 \n", + "15 3.0 \n", + "16 32.0 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 1308.75 \n", + "1 0.00 \n", + "2 559.50 \n", + "3 99.50 \n", + "4 71.50 \n", + "5 26.50 \n", + "6 189.75 \n", + "7 804.00 \n", + "8 231.50 \n", + "9 173.50 \n", + "10 390.75 \n", + "11 55.00 \n", + "12 4.50 \n", + "13 8.00 \n", + "14 7.00 \n", + "15 15.00 \n", + "16 74.75 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 89.50 \n", + "1 90.00 \n", + "2 24.00 \n", + "3 144.75 \n", + "4 0.00 \n", + "5 0.00 \n", + "6 270.50 \n", + "7 10.25 \n", + "8 20.75 \n", + "9 279.50 \n", + "10 20.00 \n", + "11 120.00 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 0.0 \n", + "1 0.0 \n", + "2 0.0 \n", + "3 0.0 \n", + "4 0.0 \n", + "5 0.0 \n", + "6 0.0 \n", + "7 0.0 \n", + "8 0.0 \n", + "9 0.0 \n", + "10 0.0 \n", + "11 0.0 \n", + "12 0.0 \n", + "13 0.0 \n", + "14 0.0 \n", + "15 0.0 \n", + "16 0.0 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 -340.00 \n", + "1 0.00 \n", + "2 -1.75 \n", + "3 66.25 \n", + "4 0.00 \n", + "5 0.00 \n", + "6 332.50 \n", + "7 0.00 \n", + "8 0.00 \n", + "9 364.50 \n", + "10 0.00 \n", + "11 50.00 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "0 1058.25 2020-01-01 2020-12-31 \n", + "1 90.00 2020-03-10 2020-05-05 \n", + "2 581.75 2020-05-18 2020-12-31 \n", + "3 310.50 2020-01-01 2020-05-04 \n", + "4 71.50 2020-08-17 2020-08-28 \n", + "5 26.50 2020-11-25 2020-11-27 \n", + "6 792.75 2020-01-02 2020-05-06 \n", + "7 814.25 2020-07-20 2020-12-31 \n", + "8 252.25 2020-07-20 2020-11-23 \n", + "9 817.50 2020-01-01 2020-05-06 \n", + "10 410.75 2020-07-06 2020-12-31 \n", + "11 225.00 2020-02-03 2020-05-06 \n", + "12 4.50 2020-02-07 2020-02-08 \n", + "13 8.00 2020-09-04 2020-09-04 \n", + "14 7.00 2020-08-21 2020-08-21 \n", + "15 15.00 2020-03-02 2020-03-04 \n", + "16 74.75 2020-05-18 2020-06-18 \n", + "17 NaN NaT NaT \n", + "18 NaN NaT NaT \n", + "19 NaN NaT NaT " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "d5b63b7e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *GiorniAssistenzaAnnoRiferimentoOre di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020inizioNormfineNorm
0Chirone RiccardoSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-10-09CHRRCR18R09E986OSalvadori PaolaBozen2019-11-19 00:00:002020-12-31366.01308.7589.500.0-340.001058.252020-01-012020-12-31
1Frei JuriSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-29FREJRU18E29A952RPeer PetraKurtatsch2020-03-10 00:00:002020-05-0557.00.0090.000.00.0090.002020-03-102020-05-05
2Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AScarduelli SoniaKaltern2020-05-18 00:00:002020-12-31228.0559.5024.000.0-1.75581.752020-05-182020-12-31
3Kajana MiaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-08-03KJNMIA18M43A952AAmbach MariaEppan2019-08-06 00:00:002020-05-04125.099.50144.750.066.25310.502020-01-012020-05-04
4Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NAmbach MariaEppan2020-08-17 00:00:002020-08-2812.071.500.000.00.0071.502020-08-172020-08-28
5Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NHuber MelanieMargreid2020-11-25 00:00:002020-11-273.026.500.000.00.0026.502020-11-252020-11-27
6Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-01-02 00:00:002020-05-06126.0189.75270.500.0332.50792.752020-01-022020-05-06
7Tomoiaga Ema MiriamSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-01TMGMRM19B41A952NPeer PetraKurtatsch2020-07-20 00:00:002020-12-31165.0804.0010.250.00.00814.252020-07-202020-12-31
8Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2020-07-20 00:00:002020-11-23127.0231.5020.750.00.00252.252020-07-202020-11-23
9Von Call DylanSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2019-02-19VNCDLN19B19A952GAmbach MariaEppan2019-11-25 00:00:002020-05-06127.0173.50279.500.0364.50817.502020-01-012020-05-06
10Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-07-06 00:00:002020-12-31179.0390.7520.000.00.00410.752020-07-062020-12-31
11Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-03 00:00:002020-05-0694.055.00120.000.050.00225.002020-02-032020-05-06
12Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-02-07 00:00:002020-02-082.04.500.000.00.004.502020-02-072020-02-08
13Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-09-04 00:00:002020-09-041.08.000.000.00.008.002020-09-042020-09-04
14Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-08-21 00:00:002020-08-211.07.000.000.00.007.002020-08-212020-08-21
15Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PHuber MelanieMargreid2020-03-02 00:00:002020-03-043.015.000.000.00.0015.002020-03-022020-03-04
16Zelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PAmbach MariaEppan2020-05-18 00:00:002020-06-1832.074.750.000.00.0074.752020-05-182020-06-18
17NaNNaNNaNNaTNaNNaNNaN10/06/2022NaTNaNNaNNaNNaNNaNNaNNaTNaT
18NaNNaNNaNNaTNaNNaNfile creato il10/06/2022NaTNaNNaNNaNNaNNaNNaNNaTNaT
19NaNNaNNaNNaTNaNNaNNaNNaNNaTNaNNaNNaNNaNNaNNaNNaTNaT
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente \\\n", + "0 Chirone Riccardo Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "1 Frei Juri Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "2 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "3 Kajana Mia Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "4 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "5 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "6 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "7 Tomoiaga Ema Miriam Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "8 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "9 Von Call Dylan Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "10 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "11 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "12 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "13 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "14 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "15 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "16 Zelger Samuel Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... \n", + "17 NaN NaN \n", + "18 NaN NaN \n", + "19 NaN NaN \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "0 Tramin 2018-10-09 CHRRCR18R09E986O \n", + "1 Tramin 2018-05-29 FREJRU18E29A952R \n", + "2 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "3 Tramin 2018-08-03 KJNMIA18M43A952A \n", + "4 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "5 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "6 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "7 Tramin 2019-02-01 TMGMRM19B41A952N \n", + "8 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "9 Tramin 2019-02-19 VNCDLN19B19A952G \n", + "10 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "11 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "12 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "13 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "14 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "15 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "16 Tramin 2018-05-08 ZLGSML18E08F132P \n", + "17 NaN NaT NaN \n", + "18 NaN NaT NaN \n", + "19 NaN NaT NaN \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 Salvadori Paola \n", + "1 Peer Petra \n", + "2 Scarduelli Sonia \n", + "3 Ambach Maria \n", + "4 Ambach Maria \n", + "5 Huber Melanie \n", + "6 Peer Petra \n", + "7 Peer Petra \n", + "8 Ambach Maria \n", + "9 Ambach Maria \n", + "10 Huber Melanie \n", + "11 Peer Petra \n", + "12 Huber Melanie \n", + "13 Ambach Maria \n", + "14 Ambach Maria \n", + "15 Huber Melanie \n", + "16 Ambach Maria \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 Bozen \n", + "1 Kurtatsch \n", + "2 Kaltern \n", + "3 Eppan \n", + "4 Eppan \n", + "5 Margreid \n", + "6 Kurtatsch \n", + "7 Kurtatsch \n", + "8 Eppan \n", + "9 Eppan \n", + "10 Margreid \n", + "11 Kurtatsch \n", + "12 Margreid \n", + "13 Eppan \n", + "14 Eppan \n", + "15 Margreid \n", + "16 Eppan \n", + "17 NaN \n", + "18 file creato il \n", + "19 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 2019-11-19 00:00:00 \n", + "1 2020-03-10 00:00:00 \n", + "2 2020-05-18 00:00:00 \n", + "3 2019-08-06 00:00:00 \n", + "4 2020-08-17 00:00:00 \n", + "5 2020-11-25 00:00:00 \n", + "6 2020-01-02 00:00:00 \n", + "7 2020-07-20 00:00:00 \n", + "8 2020-07-20 00:00:00 \n", + "9 2019-11-25 00:00:00 \n", + "10 2020-07-06 00:00:00 \n", + "11 2020-02-03 00:00:00 \n", + "12 2020-02-07 00:00:00 \n", + "13 2020-09-04 00:00:00 \n", + "14 2020-08-21 00:00:00 \n", + "15 2020-03-02 00:00:00 \n", + "16 2020-05-18 00:00:00 \n", + "17 10/06/2022 \n", + "18 10/06/2022 \n", + "19 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 2020-12-31 \n", + "1 2020-05-05 \n", + "2 2020-12-31 \n", + "3 2020-05-04 \n", + "4 2020-08-28 \n", + "5 2020-11-27 \n", + "6 2020-05-06 \n", + "7 2020-12-31 \n", + "8 2020-11-23 \n", + "9 2020-05-06 \n", + "10 2020-12-31 \n", + "11 2020-05-06 \n", + "12 2020-02-08 \n", + "13 2020-09-04 \n", + "14 2020-08-21 \n", + "15 2020-03-04 \n", + "16 2020-06-18 \n", + "17 NaT \n", + "18 NaT \n", + "19 NaT \n", + "\n", + " GiorniAssistenzaAnnoRiferimento \\\n", + "0 366.0 \n", + "1 57.0 \n", + "2 228.0 \n", + "3 125.0 \n", + "4 12.0 \n", + "5 3.0 \n", + "6 126.0 \n", + "7 165.0 \n", + "8 127.0 \n", + "9 127.0 \n", + "10 179.0 \n", + "11 94.0 \n", + "12 2.0 \n", + "13 1.0 \n", + "14 1.0 \n", + "15 3.0 \n", + "16 32.0 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 1308.75 \n", + "1 0.00 \n", + "2 559.50 \n", + "3 99.50 \n", + "4 71.50 \n", + "5 26.50 \n", + "6 189.75 \n", + "7 804.00 \n", + "8 231.50 \n", + "9 173.50 \n", + "10 390.75 \n", + "11 55.00 \n", + "12 4.50 \n", + "13 8.00 \n", + "14 7.00 \n", + "15 15.00 \n", + "16 74.75 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 89.50 \n", + "1 90.00 \n", + "2 24.00 \n", + "3 144.75 \n", + "4 0.00 \n", + "5 0.00 \n", + "6 270.50 \n", + "7 10.25 \n", + "8 20.75 \n", + "9 279.50 \n", + "10 20.00 \n", + "11 120.00 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 0.0 \n", + "1 0.0 \n", + "2 0.0 \n", + "3 0.0 \n", + "4 0.0 \n", + "5 0.0 \n", + "6 0.0 \n", + "7 0.0 \n", + "8 0.0 \n", + "9 0.0 \n", + "10 0.0 \n", + "11 0.0 \n", + "12 0.0 \n", + "13 0.0 \n", + "14 0.0 \n", + "15 0.0 \n", + "16 0.0 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 -340.00 \n", + "1 0.00 \n", + "2 -1.75 \n", + "3 66.25 \n", + "4 0.00 \n", + "5 0.00 \n", + "6 332.50 \n", + "7 0.00 \n", + "8 0.00 \n", + "9 364.50 \n", + "10 0.00 \n", + "11 50.00 \n", + "12 0.00 \n", + "13 0.00 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 0.00 \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 inizioNorm fineNorm \n", + "0 1058.25 2020-01-01 2020-12-31 \n", + "1 90.00 2020-03-10 2020-05-05 \n", + "2 581.75 2020-05-18 2020-12-31 \n", + "3 310.50 2020-01-01 2020-05-04 \n", + "4 71.50 2020-08-17 2020-08-28 \n", + "5 26.50 2020-11-25 2020-11-27 \n", + "6 792.75 2020-01-02 2020-05-06 \n", + "7 814.25 2020-07-20 2020-12-31 \n", + "8 252.25 2020-07-20 2020-11-23 \n", + "9 817.50 2020-01-01 2020-05-06 \n", + "10 410.75 2020-07-06 2020-12-31 \n", + "11 225.00 2020-02-03 2020-05-06 \n", + "12 4.50 2020-02-07 2020-02-08 \n", + "13 8.00 2020-09-04 2020-09-04 \n", + "14 7.00 2020-08-21 2020-08-21 \n", + "15 15.00 2020-03-02 2020-03-04 \n", + "16 74.75 2020-05-18 2020-06-18 \n", + "17 NaN NaT NaT \n", + "18 NaN NaT NaT \n", + "19 NaN NaT NaT " + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2a74dd9", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/EsempioTimeSeries.xlsx b/pages/Jupyter/EsempioTimeSeries.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7339fcc1e0217365d2cd9100c3ee238e62b21f86 Binary files /dev/null and b/pages/Jupyter/EsempioTimeSeries.xlsx differ diff --git a/pages/Jupyter/EsempioTimeSeries2.xlsx b/pages/Jupyter/EsempioTimeSeries2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b9dc0ead4661c7c4ea3e7e0388e1921ef3fda0f2 Binary files /dev/null and b/pages/Jupyter/EsempioTimeSeries2.xlsx differ diff --git a/pages/Jupyter/EsempioTimeSeries3.xlsx b/pages/Jupyter/EsempioTimeSeries3.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e582a093012752748e0b76952943e76136997312 Binary files /dev/null and b/pages/Jupyter/EsempioTimeSeries3.xlsx differ diff --git a/pages/Jupyter/EsempioTimeSeries4.xlsx b/pages/Jupyter/EsempioTimeSeries4.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..22bd9993a9fecd45cd390091e92ee7c73eb586b5 Binary files /dev/null and b/pages/Jupyter/EsempioTimeSeries4.xlsx differ diff --git a/pages/Jupyter/Fehler Kind Mehrfachnennung 2.xlsx b/pages/Jupyter/Fehler Kind Mehrfachnennung 2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fc094d1b1aac7195fd632556cfa8638598a4cc48 Binary files /dev/null and b/pages/Jupyter/Fehler Kind Mehrfachnennung 2.xlsx differ diff --git a/pages/Jupyter/Fehler Kind Mehrfachnennung.xlsx b/pages/Jupyter/Fehler Kind Mehrfachnennung.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..aa3930002822228192afbe23837eada6949528f9 Binary files /dev/null and b/pages/Jupyter/Fehler Kind Mehrfachnennung.xlsx differ diff --git a/pages/Jupyter/KindMehrfachnennung.ipynb b/pages/Jupyter/KindMehrfachnennung.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..c02f2f65228ed21adacd99d3cdcd9cffecdf1d5e --- /dev/null +++ b/pages/Jupyter/KindMehrfachnennung.ipynb @@ -0,0 +1,1819 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 30, + "id": "27b85b04", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io\n", + "import copy\n", + "df={}" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "5e8829fe", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "d7bf08ae", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.8/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "df1 = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "#df2 = df2.drop(df2.iloc[:,10:], axis=1)\n", + "df['s0']=df1\n", + "df['s1']=df2" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d0e8d71f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Verifica del rispetto del contingente di cui all'articolo 7 della Deliberazione della Giunta Provinciale n. 1054/2017 \\nai fini del riconoscimento del contributo provinciale 2020 per il servizio di microstruttura ai Comuni (articolo 3, comma 3, della Deliberazione della Giunta Provinciale Nr. 666/2019)Unnamed: 1Unnamed: 2Unnamed: 3Unnamed: 4Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9Unnamed: 10Unnamed: 11Unnamed: 12Unnamed: 13Unnamed: 14
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1MicrostrutturaBolzano, Piazza Fiera, 1, Xenia (aziendale)NaNNaNNaNNaNNaNNaNNaN2019NaNNaNNaNNaNNaN
2Ente gestoreXenia Cooperativa Sociale OnlusNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxxSe utente comunale, indicare le ore rendiconta...NaNNaNEntrate da compartecipazione tariffaria relati...NaNNaNNaNNaNNaN
................................................
65NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
66NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
67NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
68NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
69NaNNaNNaNNaNNaNNaN145860042972.07NaNNaNNaNNaNNaN
\n", + "

70 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " Verifica del rispetto del contingente di cui all'articolo 7 della Deliberazione della Giunta Provinciale n. 1054/2017 \\nai fini del riconoscimento del contributo provinciale 2020 per il servizio di microstruttura ai Comuni (articolo 3, comma 3, della Deliberazione della Giunta Provinciale Nr. 666/2019) \\\n", + "0 NaN \n", + "1 Microstruttura \n", + "2 Ente gestore \n", + "3 NaN \n", + "4 bambini \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 \\\n", + "0 NaN NaN \n", + "1 Bolzano, Piazza Fiera, 1, Xenia (aziendale) NaN \n", + "2 Xenia Cooperativa Sociale Onlus NaN \n", + "3 NaN NaN \n", + "4 NaN utente aziendale o comunale \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " Unnamed: 3 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " Unnamed: 4 Unnamed: 5 \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " Unnamed: 6 Unnamed: 7 Unnamed: 8 \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 Se utente comunale, indicare le ore rendiconta... NaN NaN \n", + ".. ... ... ... \n", + "65 NaN NaN NaN \n", + "66 NaN NaN NaN \n", + "67 NaN NaN NaN \n", + "68 NaN NaN NaN \n", + "69 14586 0 0 \n", + "\n", + " Unnamed: 9 Unnamed: 10 \\\n", + "0 NaN NaN \n", + "1 2019 NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Entrate da compartecipazione tariffaria relati... NaN \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 42972.07 NaN \n", + "\n", + " Unnamed: 11 Unnamed: 12 Unnamed: 13 Unnamed: 14 \n", + "0 NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN \n", + ".. ... ... ... ... \n", + "65 NaN NaN NaN NaN \n", + "66 NaN NaN NaN NaN \n", + "67 NaN NaN NaN NaN \n", + "68 NaN NaN NaN NaN \n", + "69 NaN NaN NaN NaN \n", + "\n", + "[70 rows x 15 columns]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df['s1']" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "4d222c8c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Verifica del rispetto del contingente di cui all'articolo 7 della Deliberazione della Giunta Provinciale n. 1054/2017 \\nai fini del riconoscimento del contributo provinciale 2020 per il servizio di microstruttura ai Comuni (articolo 3, comma 3, della Deliberazione della Giunta Provinciale Nr. 666/2019)Unnamed: 1Unnamed: 2Unnamed: 3Unnamed: 4Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1MicrostrutturaBolzano, Piazza Fiera, 1, Xenia (aziendale)NaNNaNNaNNaNNaNNaNNaN2019
2Ente gestoreXenia Cooperativa Sociale OnlusNaNNaNNaNNaNNaNNaNNaNNaN
3NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxxSe utente comunale, indicare le ore rendiconta...NaNNaNEntrate da compartecipazione tariffaria relati...
.................................
65NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
66NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
67NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
68NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
69NaNNaNNaNNaNNaNNaN145860042972.07
\n", + "

70 rows × 10 columns

\n", + "
" + ], + "text/plain": [ + " Verifica del rispetto del contingente di cui all'articolo 7 della Deliberazione della Giunta Provinciale n. 1054/2017 \\nai fini del riconoscimento del contributo provinciale 2020 per il servizio di microstruttura ai Comuni (articolo 3, comma 3, della Deliberazione della Giunta Provinciale Nr. 666/2019) \\\n", + "0 NaN \n", + "1 Microstruttura \n", + "2 Ente gestore \n", + "3 NaN \n", + "4 bambini \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 \\\n", + "0 NaN NaN \n", + "1 Bolzano, Piazza Fiera, 1, Xenia (aziendale) NaN \n", + "2 Xenia Cooperativa Sociale Onlus NaN \n", + "3 NaN NaN \n", + "4 NaN utente aziendale o comunale \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " Unnamed: 3 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " Unnamed: 4 Unnamed: 5 \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " Unnamed: 6 Unnamed: 7 Unnamed: 8 \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 Se utente comunale, indicare le ore rendiconta... NaN NaN \n", + ".. ... ... ... \n", + "65 NaN NaN NaN \n", + "66 NaN NaN NaN \n", + "67 NaN NaN NaN \n", + "68 NaN NaN NaN \n", + "69 14586 0 0 \n", + "\n", + " Unnamed: 9 \n", + "0 NaN \n", + "1 2019 \n", + "2 NaN \n", + "3 NaN \n", + "4 Entrate da compartecipazione tariffaria relati... \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 42972.07 \n", + "\n", + "[70 rows x 10 columns]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df['s1'].drop(df['s1'].iloc[:,10:], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "5df9298f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
CognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733Entrate
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1MicrostrutturaBolzano, Piazza Fiera, 1, Xenia (aziendale)NaNNaNNaNNaNNaNNaNNaN2019
2Ente gestoreXenia Cooperativa Sociale OnlusNaNNaNNaNNaNNaNNaNNaNNaN
3NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxxSe utente comunale, indicare le ore rendiconta...NaNNaNEntrate da compartecipazione tariffaria relati...
.................................
65NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
66NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
67NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
68NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
69NaNNaNNaNNaNNaNNaN145860042972.07
\n", + "

70 rows × 10 columns

\n", + "
" + ], + "text/plain": [ + " Cognome Nome \\\n", + "0 NaN NaN \n", + "1 Microstruttura Bolzano, Piazza Fiera, 1, Xenia (aziendale) \n", + "2 Ente gestore Xenia Cooperativa Sociale Onlus \n", + "3 NaN NaN \n", + "4 bambini NaN \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " utente \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 utente aziendale o comunale \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " ComuneProvenienza \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 NaN \n", + "\n", + " DataInizio DataFine \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + ".. ... ... \n", + "65 NaN NaN \n", + "66 NaN NaN \n", + "67 NaN NaN \n", + "68 NaN NaN \n", + "69 NaN NaN \n", + "\n", + " delibera666 delibera543 delibera733 \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 Se utente comunale, indicare le ore rendiconta... NaN NaN \n", + ".. ... ... ... \n", + "65 NaN NaN NaN \n", + "66 NaN NaN NaN \n", + "67 NaN NaN NaN \n", + "68 NaN NaN NaN \n", + "69 14586 0 0 \n", + "\n", + " Entrate \n", + "0 NaN \n", + "1 2019 \n", + "2 NaN \n", + "3 NaN \n", + "4 Entrate da compartecipazione tariffaria relati... \n", + ".. ... \n", + "65 NaN \n", + "66 NaN \n", + "67 NaN \n", + "68 NaN \n", + "69 42972.07 \n", + "\n", + "[70 rows x 10 columns]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "476ed272", + "metadata": {}, + "outputs": [], + "source": [ + "df = {}\n", + "type(df)\n", + "df[\"sheet0\"] = None\n", + "df[\"sheet1\"] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "c8365ac8", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "d3905bd3", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "19222870", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce').isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce').isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "e09d0327", + "metadata": {}, + "outputs": [], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "c4549fa2", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "10dddc1a", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "c97c0d9e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine, delibera666, delibera543, delibera733, Entrate, errData]\n", + "Index: []" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "b9771f2b", + "metadata": {}, + "outputs": [], + "source": [ + "df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") " + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "cb1bb9e9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"sheet0\"] = df1\n", + "df[\"sheet1\"] = df2" + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "fa87a9ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizioDataFine_xEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataFine_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-12-3150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleTerlano2019-09-30508NaNNaN1854.2<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x ComuneProvenienza_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataFine_y delibera666 delibera543 delibera733 Entrate \\\n", + "0 Avelengo 2020-12-31 500 100 10 750 \n", + "1 Terlano 2019-09-30 508 NaN NaN 1854.2 \n", + "\n", + " errData \n", + "0 \n", + "1 " + ] + }, + "execution_count": 109, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff = pd.merge(df1, df2, on=['Cognome','Nome','DataInizio'], how='inner')\n", + "mergedStuff" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "id": "80b9dc04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizio_xDataFineEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataInizio_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome utente_x \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst comunale \n", + "\n", + " ComuneProvenienza_x DataInizio_x DataFine \\\n", + "0 Andriano 2020-01-01 2020-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataInizio_y delibera666 delibera543 delibera733 \\\n", + "0 Avelengo 2020-01-01 500 100 10 \n", + "\n", + " Entrate errData \n", + "0 750 " + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff2 = pd.merge(df1, df2, on=['Cognome','Nome','DataFine'], how='inner')\n", + "mergedStuff2" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "id": "5c270e79", + "metadata": {}, + "outputs": [], + "source": [ + "m = pd.merge(mergedStuff, mergedStuff2, on=['Cognome','Nome'], how='outer')" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "id": "d8b57ba9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_x_xMicrostruttura_x_xCognomeNomeutente_x_xComuneProvenienza_x_xDataInizioDataFine_xEnte_y_xMicrostruttura_y_x...Ente_y_yMicrostruttura_y_yutente_y_yComuneProvenienza_y_yDataInizio_ydelibera666_ydelibera543_ydelibera733_yEntrate_yerrData_y
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine......Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine......NaNNaNNaNNaNNaTNaNNaNNaNNaN<NA>
\n", + "

2 rows × 34 columns

\n", + "
" + ], + "text/plain": [ + " Ente_x_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x_x ComuneProvenienza_x_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y_x \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y_x ... \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... ... \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... ... \n", + "\n", + " Ente_y_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 NaN \n", + "\n", + " Microstruttura_y_y utente_y_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 NaN NaN \n", + "\n", + " ComuneProvenienza_y_y DataInizio_y delibera666_y delibera543_y \\\n", + "0 Avelengo 2020-01-01 500 100 \n", + "1 NaN NaT NaN NaN \n", + "\n", + " delibera733_y Entrate_y errData_y \n", + "0 10 750 \n", + "1 NaN NaN \n", + "\n", + "[2 rows x 34 columns]" + ] + }, + "execution_count": 133, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "id": "abdb5e65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizioDataFine_xEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataFine_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-12-3150010010750<NA>
1Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...MarcherLucreziacomunaleTerlano2017-01-012018-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleTerlano2019-09-30508NaNNaN1854.2<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "1 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst \n", + "1 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Marcher Lucrezia \n", + "\n", + " utente_x ComuneProvenienza_x DataInizio DataFine_x \\\n", + "0 comunale Andriano 2020-01-01 2020-12-31 \n", + "1 comunale Terlano 2017-01-01 2018-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "1 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "1 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataFine_y delibera666 delibera543 delibera733 Entrate \\\n", + "0 Avelengo 2020-12-31 500 100 10 750 \n", + "1 Terlano 2019-09-30 508 NaN NaN 1854.2 \n", + "\n", + " errData \n", + "0 \n", + "1 " + ] + }, + "execution_count": 121, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "id": "b8551529", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Ente_xMicrostruttura_xCognomeNomeutente_xComuneProvenienza_xDataInizio_xDataFineEnte_yMicrostruttura_yutente_yComuneProvenienza_yDataInizio_ydelibera666delibera543delibera733EntrateerrData
0Cooperativa sociale CoccinellaAppiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi...HansWurstcomunaleAndriano2020-01-012020-12-31Cooperativa Sociale Primi PassiBolzano, Lungo Talvera S. Quirino, 10, Coccine...comunaleAvelengo2020-01-0150010010750<NA>
\n", + "
" + ], + "text/plain": [ + " Ente_x \\\n", + "0 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura_x Cognome Nome utente_x \\\n", + "0 Appiano s.s.d.v. - S. Michele, Via Sill, 3 (Vi... Hans Wurst comunale \n", + "\n", + " ComuneProvenienza_x DataInizio_x DataFine \\\n", + "0 Andriano 2020-01-01 2020-12-31 \n", + "\n", + " Ente_y \\\n", + "0 Cooperativa Sociale Primi Passi \n", + "\n", + " Microstruttura_y utente_y \\\n", + "0 Bolzano, Lungo Talvera S. Quirino, 10, Coccine... comunale \n", + "\n", + " ComuneProvenienza_y DataInizio_y delibera666 delibera543 delibera733 \\\n", + "0 Avelengo 2020-01-01 500 100 10 \n", + "\n", + " Entrate errData \n", + "0 750 " + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mergedStuff2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbe6b90c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled.ipynb b/pages/Jupyter/Untitled.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..fa25c978578a005bd1d5c32b2fbdd8ad8541dbe2 --- /dev/null +++ b/pages/Jupyter/Untitled.ipynb @@ -0,0 +1,1907 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 978, + "id": "b43a938a", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import streamlit as st\n", + "import datetime as dt\n", + "fn = './errorfiles/Erklärung Gemeinden Jahr 2020 Ahrntal_corr.xlsx'" + ] + }, + { + "cell_type": "code", + "execution_count": 979, + "id": "06cb6fc3", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn)#header=[3,4,8])" + ] + }, + { + "cell_type": "code", + "execution_count": 980, + "id": "79ce8c8c", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 981, + "id": "a2a23785", + "metadata": {}, + "outputs": [], + "source": [ + "t = traeger[3].title()" + ] + }, + { + "cell_type": "code", + "execution_count": 982, + "id": "7da435ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben'" + ] + }, + "execution_count": 982, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "t" + ] + }, + { + "cell_type": "code", + "execution_count": 983, + "id": "cd385105", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde=df.iloc[3]" + ] + }, + { + "cell_type": "code", + "execution_count": 984, + "id": "40a5527f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Ahrntal'" + ] + }, + "execution_count": 984, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde[3]" + ] + }, + { + "cell_type": "code", + "execution_count": 985, + "id": "3b5fdde6", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome e nome bambino\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020\",\n", + " \"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2020\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 986, + "id": "3654b61d", + "metadata": {}, + "outputs": [], + "source": [ + " df = df.drop(labels=range(0,8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 987, + "id": "243b0667", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 988, + "id": "9e52c89a", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 989, + "id": "9a54d988", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 997, + "id": "9b07f1fa", + "metadata": {}, + "outputs": [], + "source": [ + "condizione = pd.isnull(df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 999, + "id": "8f06d102", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2020" + ] + }, + { + "cell_type": "code", + "execution_count": 1005, + "id": "7bed0cdc", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = \"12-31-\" + str(ar)\n", + "df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"].astype('datetime64[ns]')" + ] + }, + { + "cell_type": "code", + "execution_count": 1006, + "id": "f53ad7a3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020
81.0Ajardi Johannes2017-09-30 00:00:00JRDJNN17P30B220GKirchler JudithSt. Peter In Ahrntal2018-02-16 00:00:002020-09-02442.5188.5NaN50.75681.75
92.0Ajardi Josef2019-10-02 00:00:00JRDJSF19R02B220YKirchler JudithSt. Peter In Ahrntal2020-02-24 00:00:002020-12-31641.5194.5NaN50.75886.75
103.0Eder Nicolas Adele2019-01-06 00:00:00DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-02-12 00:00:002020-05-0622102NaN84208
113.0Eder Nicolas Adele2019-01-06 00:00:00DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-09-17 00:00:002020-12-31130.7512NaN0142.75
124.0Gartner Max2017-03-04 00:00:00GRTMXA17C04B220JKirchler ClaudiaSt. Jakob in Ahrntal2019-06-03 00:00:002020-05-0681118NaN0199
136.0Hofer Julian2020-04-16 00:00:00HFRJLN20D16B220PKirchler IrmgardAhrntal2020-08-13 00:00:002020-12-3141933NaN0452
145.0Hofer Hanna2018-09-05 00:00:00HFRHNN18P45B220DKirchler IrmgardAhrntal2020-09-14 00:00:002020-12-3116720NaN0187
157.0Hopfgartner Toni2018-01-31 00:00:00HPFTNO18A31B220PKammerlander VerenaAhrntal2019-02-11 00:00:002020-12-31511.25160NaN32703.25
168.0Innerbichler Simon2018-06-24 00:00:00NNRSMN18H24B220FKirchler JudithSt. Peter In Ahrntal2019-08-20 00:00:002020-12-31880.75265NaN108.251254
179.0Kirchler Isabel2018-02-07 00:00:00KRCSBL18B47B220NKammerlander VerenaAhrntal2019-01-02 00:00:002020-12-31396120NaN32548
1810.0Kirchler Jana Rosa2017-10-02 00:00:00KRCJRS17R42B220OKirchler IrmgardAhrntal2018-11-02 00:00:002020-08-27262.75117NaN45424.75
1911.0Lechner Lisa2018-06-09 00:00:00LCHLSI18H49B220JKirchler ClaudiaSt. Jakob in Ahrntal2019-12-02 00:00:002020-05-06112104NaN92308
2011.0Lechner Lisa2018-06-09 00:00:00LCHLSI18H49B220JKirchler ClaudiaSt. Jakob in Ahrntal2020-07-01 00:00:002020-12-3126812NaN0280
2112.0Lechner Pia2017-10-12 00:00:00LCHPIA17R52B220NKirchler ClaudiaSt. Jakob in Ahrntal2019-10-02 00:00:002020-05-0688104NaN0192
2213.0Oberhauser Anton2018-05-13 00:00:00BRHNTN18E13B220EKirchler IrmgardAhrntal2020-09-09 00:00:002020-12-31279.7525NaN0304.75
2314.0Oberhofer Greta2018-11-09 00:00:00BRHGRT18S49B220RKammerlander VerenaAhrntal2019-12-02 00:00:002020-12-31531143.25NaN38.75713
2415.0Oberlechner Emilia2018-09-14 00:00:00BRLMLE18P54B220XKammerlander VerenaAhrntal2020-01-08 00:00:002020-12-31779240NaN361055
2516.0Obermair Johanna2017-09-26 00:00:00BRMJNN17P66B220NKirchler JudithSt. Peter In Ahrntal2018-07-03 00:00:002020-08-28203.25104NaN87.5394.75
2617.0Obermair Theresa2019-06-06 00:00:00BRMTRS19H46A952AKirchler JudithSt. Peter In Ahrntal2020-10-02 00:00:002020-12-31116.7513.5NaN0130.25
2718.0Obermair Tommi Jona2019-06-07 00:00:00BRMTMJ19H07B220DKirchler ClaudiaSt. Jakob in Ahrntal2020-09-14 00:00:002020-12-3114812NaN0160
2819.0Oberschmied Matilda2019-08-07 00:00:00BRSMLD19M47B220BKirchler ClaudiaSt. Jakob in Ahrntal2020-09-09 00:00:002020-12-312486.25NaN0254.25
2920.0Pareiner Jakob2019-07-31 00:00:00PRNJKB19L31B220ZKirchler IrmgardAhrntal2020-10-05 00:00:002020-12-31165.750NaN0165.75
3021.0Ploner Greti2018-04-23 00:00:00PLNGRT18D63B220AKirchler IrmgardAhrntal2019-08-19 00:00:002020-12-31747.75147NaN26.5921.25
3122.0Ruiu Nina2017-03-25 00:00:00RUINNI17C65B220YKirchler IrmgardAhrntal2018-03-01 00:00:002020-10-13554.75176.5NaN54.5785.75
3223.0Steger Elias2018-03-19 00:00:00STGLSE18C19B220NKirchler IrmgardAhrntal2019-07-19 00:00:002020-12-31544.5164NaN92.75801.25
3324.0Steger Ida2017-09-20 00:00:00STGDIA17P60B220QKirchler ClaudiaSt. Jakob in Ahrntal2019-04-02 00:00:002020-09-03405153NaN27585
3425.0Steinhauser Ida2017-07-07 00:00:00STNDIA17L47B220KKirchler ClaudiaSt. Jakob in Ahrntal2020-06-22 00:00:002020-09-04178.750NaN0178.75
3526.0Stolzlechner Clara2018-01-02 00:00:00STLCLR18A42B220HKirchler JudithSt. Peter In Ahrntal2019-01-09 00:00:002020-12-31657.25198NaN76.5931.75
3627.0Weger Sam2017-08-02 00:00:00WGRSMA17M02B220HKirchler IrmgardAhrntal2019-09-09 00:00:002020-09-04351.75118.75NaN21.75492.25
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 Ajardi Johannes 2017-09-30 00:00:00 \n", + "9 2.0 Ajardi Josef 2019-10-02 00:00:00 \n", + "10 3.0 Eder Nicolas Adele 2019-01-06 00:00:00 \n", + "11 3.0 Eder Nicolas Adele 2019-01-06 00:00:00 \n", + "12 4.0 Gartner Max 2017-03-04 00:00:00 \n", + "13 6.0 Hofer Julian 2020-04-16 00:00:00 \n", + "14 5.0 Hofer Hanna 2018-09-05 00:00:00 \n", + "15 7.0 Hopfgartner Toni 2018-01-31 00:00:00 \n", + "16 8.0 Innerbichler Simon 2018-06-24 00:00:00 \n", + "17 9.0 Kirchler Isabel 2018-02-07 00:00:00 \n", + "18 10.0 Kirchler Jana Rosa 2017-10-02 00:00:00 \n", + "19 11.0 Lechner Lisa 2018-06-09 00:00:00 \n", + "20 11.0 Lechner Lisa 2018-06-09 00:00:00 \n", + "21 12.0 Lechner Pia 2017-10-12 00:00:00 \n", + "22 13.0 Oberhauser Anton 2018-05-13 00:00:00 \n", + "23 14.0 Oberhofer Greta 2018-11-09 00:00:00 \n", + "24 15.0 Oberlechner Emilia 2018-09-14 00:00:00 \n", + "25 16.0 Obermair Johanna 2017-09-26 00:00:00 \n", + "26 17.0 Obermair Theresa 2019-06-06 00:00:00 \n", + "27 18.0 Obermair Tommi Jona 2019-06-07 00:00:00 \n", + "28 19.0 Oberschmied Matilda 2019-08-07 00:00:00 \n", + "29 20.0 Pareiner Jakob 2019-07-31 00:00:00 \n", + "30 21.0 Ploner Greti 2018-04-23 00:00:00 \n", + "31 22.0 Ruiu Nina 2017-03-25 00:00:00 \n", + "32 23.0 Steger Elias 2018-03-19 00:00:00 \n", + "33 24.0 Steger Ida 2017-09-20 00:00:00 \n", + "34 25.0 Steinhauser Ida 2017-07-07 00:00:00 \n", + "35 26.0 Stolzlechner Clara 2018-01-02 00:00:00 \n", + "36 27.0 Weger Sam 2017-08-02 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 JRDJNN17P30B220G Kirchler Judith \n", + "9 JRDJSF19R02B220Y Kirchler Judith \n", + "10 DRNDLA19A46Z131E Kirchler Claudia \n", + "11 DRNDLA19A46Z131E Kirchler Claudia \n", + "12 GRTMXA17C04B220J Kirchler Claudia \n", + "13 HFRJLN20D16B220P Kirchler Irmgard \n", + "14 HFRHNN18P45B220D Kirchler Irmgard \n", + "15 HPFTNO18A31B220P Kammerlander Verena \n", + "16 NNRSMN18H24B220F Kirchler Judith \n", + "17 KRCSBL18B47B220N Kammerlander Verena \n", + "18 KRCJRS17R42B220O Kirchler Irmgard \n", + "19 LCHLSI18H49B220J Kirchler Claudia \n", + "20 LCHLSI18H49B220J Kirchler Claudia \n", + "21 LCHPIA17R52B220N Kirchler Claudia \n", + "22 BRHNTN18E13B220E Kirchler Irmgard \n", + "23 BRHGRT18S49B220R Kammerlander Verena \n", + "24 BRLMLE18P54B220X Kammerlander Verena \n", + "25 BRMJNN17P66B220N Kirchler Judith \n", + "26 BRMTRS19H46A952A Kirchler Judith \n", + "27 BRMTMJ19H07B220D Kirchler Claudia \n", + "28 BRSMLD19M47B220B Kirchler Claudia \n", + "29 PRNJKB19L31B220Z Kirchler Irmgard \n", + "30 PLNGRT18D63B220A Kirchler Irmgard \n", + "31 RUINNI17C65B220Y Kirchler Irmgard \n", + "32 STGLSE18C19B220N Kirchler Irmgard \n", + "33 STGDIA17P60B220Q Kirchler Claudia \n", + "34 STNDIA17L47B220K Kirchler Claudia \n", + "35 STLCLR18A42B220H Kirchler Judith \n", + "36 WGRSMA17M02B220H Kirchler Irmgard \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 St. Peter In Ahrntal \n", + "9 St. Peter In Ahrntal \n", + "10 St. Jakob in Ahrntal \n", + "11 St. Jakob in Ahrntal \n", + "12 St. Jakob in Ahrntal \n", + "13 Ahrntal \n", + "14 Ahrntal \n", + "15 Ahrntal \n", + "16 St. Peter In Ahrntal \n", + "17 Ahrntal \n", + "18 Ahrntal \n", + "19 St. Jakob in Ahrntal \n", + "20 St. Jakob in Ahrntal \n", + "21 St. Jakob in Ahrntal \n", + "22 Ahrntal \n", + "23 Ahrntal \n", + "24 Ahrntal \n", + "25 St. Peter In Ahrntal \n", + "26 St. Peter In Ahrntal \n", + "27 St. Jakob in Ahrntal \n", + "28 St. Jakob in Ahrntal \n", + "29 Ahrntal \n", + "30 Ahrntal \n", + "31 Ahrntal \n", + "32 Ahrntal \n", + "33 St. Jakob in Ahrntal \n", + "34 St. Jakob in Ahrntal \n", + "35 St. Peter In Ahrntal \n", + "36 Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2018-02-16 00:00:00 \n", + "9 2020-02-24 00:00:00 \n", + "10 2020-02-12 00:00:00 \n", + "11 2020-09-17 00:00:00 \n", + "12 2019-06-03 00:00:00 \n", + "13 2020-08-13 00:00:00 \n", + "14 2020-09-14 00:00:00 \n", + "15 2019-02-11 00:00:00 \n", + "16 2019-08-20 00:00:00 \n", + "17 2019-01-02 00:00:00 \n", + "18 2018-11-02 00:00:00 \n", + "19 2019-12-02 00:00:00 \n", + "20 2020-07-01 00:00:00 \n", + "21 2019-10-02 00:00:00 \n", + "22 2020-09-09 00:00:00 \n", + "23 2019-12-02 00:00:00 \n", + "24 2020-01-08 00:00:00 \n", + "25 2018-07-03 00:00:00 \n", + "26 2020-10-02 00:00:00 \n", + "27 2020-09-14 00:00:00 \n", + "28 2020-09-09 00:00:00 \n", + "29 2020-10-05 00:00:00 \n", + "30 2019-08-19 00:00:00 \n", + "31 2018-03-01 00:00:00 \n", + "32 2019-07-19 00:00:00 \n", + "33 2019-04-02 00:00:00 \n", + "34 2020-06-22 00:00:00 \n", + "35 2019-01-09 00:00:00 \n", + "36 2019-09-09 00:00:00 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2020-09-02 \n", + "9 2020-12-31 \n", + "10 2020-05-06 \n", + "11 2020-12-31 \n", + "12 2020-05-06 \n", + "13 2020-12-31 \n", + "14 2020-12-31 \n", + "15 2020-12-31 \n", + "16 2020-12-31 \n", + "17 2020-12-31 \n", + "18 2020-08-27 \n", + "19 2020-05-06 \n", + "20 2020-12-31 \n", + "21 2020-05-06 \n", + "22 2020-12-31 \n", + "23 2020-12-31 \n", + "24 2020-12-31 \n", + "25 2020-08-28 \n", + "26 2020-12-31 \n", + "27 2020-12-31 \n", + "28 2020-12-31 \n", + "29 2020-12-31 \n", + "30 2020-12-31 \n", + "31 2020-10-13 \n", + "32 2020-12-31 \n", + "33 2020-09-03 \n", + "34 2020-09-04 \n", + "35 2020-12-31 \n", + "36 2020-09-04 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 442.5 \n", + "9 641.5 \n", + "10 22 \n", + "11 130.75 \n", + "12 81 \n", + "13 419 \n", + "14 167 \n", + "15 511.25 \n", + "16 880.75 \n", + "17 396 \n", + "18 262.75 \n", + "19 112 \n", + "20 268 \n", + "21 88 \n", + "22 279.75 \n", + "23 531 \n", + "24 779 \n", + "25 203.25 \n", + "26 116.75 \n", + "27 148 \n", + "28 248 \n", + "29 165.75 \n", + "30 747.75 \n", + "31 554.75 \n", + "32 544.5 \n", + "33 405 \n", + "34 178.75 \n", + "35 657.25 \n", + "36 351.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "8 188.5 \n", + "9 194.5 \n", + "10 102 \n", + "11 12 \n", + "12 118 \n", + "13 33 \n", + "14 20 \n", + "15 160 \n", + "16 265 \n", + "17 120 \n", + "18 117 \n", + "19 104 \n", + "20 12 \n", + "21 104 \n", + "22 25 \n", + "23 143.25 \n", + "24 240 \n", + "25 104 \n", + "26 13.5 \n", + "27 12 \n", + "28 6.25 \n", + "29 0 \n", + "30 147 \n", + "31 176.5 \n", + "32 164 \n", + "33 153 \n", + "34 0 \n", + "35 198 \n", + "36 118.75 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "8 NaN \n", + "9 NaN \n", + "10 NaN \n", + "11 NaN \n", + "12 NaN \n", + "13 NaN \n", + "14 NaN \n", + "15 NaN \n", + "16 NaN \n", + "17 NaN \n", + "18 NaN \n", + "19 NaN \n", + "20 NaN \n", + "21 NaN \n", + "22 NaN \n", + "23 NaN \n", + "24 NaN \n", + "25 NaN \n", + "26 NaN \n", + "27 NaN \n", + "28 NaN \n", + "29 NaN \n", + "30 NaN \n", + "31 NaN \n", + "32 NaN \n", + "33 NaN \n", + "34 NaN \n", + "35 NaN \n", + "36 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "8 50.75 \n", + "9 50.75 \n", + "10 84 \n", + "11 0 \n", + "12 0 \n", + "13 0 \n", + "14 0 \n", + "15 32 \n", + "16 108.25 \n", + "17 32 \n", + "18 45 \n", + "19 92 \n", + "20 0 \n", + "21 0 \n", + "22 0 \n", + "23 38.75 \n", + "24 36 \n", + "25 87.5 \n", + "26 0 \n", + "27 0 \n", + "28 0 \n", + "29 0 \n", + "30 26.5 \n", + "31 54.5 \n", + "32 92.75 \n", + "33 27 \n", + "34 0 \n", + "35 76.5 \n", + "36 21.75 \n", + "\n", + " Ore totali rendicontate per il 2020 \n", + "8 681.75 \n", + "9 886.75 \n", + "10 208 \n", + "11 142.75 \n", + "12 199 \n", + "13 452 \n", + "14 187 \n", + "15 703.25 \n", + "16 1254 \n", + "17 548 \n", + "18 424.75 \n", + "19 308 \n", + "20 280 \n", + "21 192 \n", + "22 304.75 \n", + "23 713 \n", + "24 1055 \n", + "25 394.75 \n", + "26 130.25 \n", + "27 160 \n", + "28 254.25 \n", + "29 165.75 \n", + "30 921.25 \n", + "31 785.75 \n", + "32 801.25 \n", + "33 585 \n", + "34 178.75 \n", + "35 931.75 \n", + "36 492.25 " + ] + }, + "execution_count": 1006, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 908, + "id": "25deb868", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Missing column provided to 'parse_dates': 'Data di nascita, Data fine contratto\n(o data fine assistenza se diversa) *, Data inizio contratto (o data inizio assistenza se diversa)'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [908]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m df \u001b[38;5;241m=\u001b[39m \u001b[43mpd\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread_excel\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfn\u001b[49m\u001b[43m,\u001b[49m\u001b[43mparse_dates\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mData di nascita\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mData fine contratto\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m(o data fine assistenza se diversa) *\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mData inizio contratto (o data inizio assistenza se diversa)\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheader\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m8\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/util/_decorators.py:311\u001b[0m, in \u001b[0;36mdeprecate_nonkeyword_arguments..decorate..wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 305\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(args) \u001b[38;5;241m>\u001b[39m num_allow_args:\n\u001b[1;32m 306\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[1;32m 307\u001b[0m msg\u001b[38;5;241m.\u001b[39mformat(arguments\u001b[38;5;241m=\u001b[39marguments),\n\u001b[1;32m 308\u001b[0m \u001b[38;5;167;01mFutureWarning\u001b[39;00m,\n\u001b[1;32m 309\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39mstacklevel,\n\u001b[1;32m 310\u001b[0m )\n\u001b[0;32m--> 311\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/excel/_base.py:465\u001b[0m, in \u001b[0;36mread_excel\u001b[0;34m(io, sheet_name, header, names, index_col, usecols, squeeze, dtype, engine, converters, true_values, false_values, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, parse_dates, date_parser, thousands, decimal, comment, skipfooter, convert_float, mangle_dupe_cols, storage_options)\u001b[0m\n\u001b[1;32m 459\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 460\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEngine should not be specified when passing \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 461\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124man ExcelFile - ExcelFile already has the engine set\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 462\u001b[0m )\n\u001b[1;32m 464\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 465\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43mio\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 466\u001b[0m \u001b[43m \u001b[49m\u001b[43msheet_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msheet_name\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 467\u001b[0m \u001b[43m \u001b[49m\u001b[43mheader\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheader\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 468\u001b[0m \u001b[43m \u001b[49m\u001b[43mnames\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnames\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 469\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex_col\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindex_col\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 470\u001b[0m \u001b[43m \u001b[49m\u001b[43musecols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43musecols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 471\u001b[0m \u001b[43m \u001b[49m\u001b[43msqueeze\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msqueeze\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 472\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 473\u001b[0m \u001b[43m \u001b[49m\u001b[43mconverters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconverters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 474\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrue_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrue_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 475\u001b[0m \u001b[43m \u001b[49m\u001b[43mfalse_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfalse_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 476\u001b[0m \u001b[43m \u001b[49m\u001b[43mskiprows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskiprows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 477\u001b[0m \u001b[43m \u001b[49m\u001b[43mnrows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnrows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 478\u001b[0m \u001b[43m \u001b[49m\u001b[43mna_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mna_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 479\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeep_default_na\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeep_default_na\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 480\u001b[0m \u001b[43m \u001b[49m\u001b[43mna_filter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mna_filter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 481\u001b[0m \u001b[43m \u001b[49m\u001b[43mverbose\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mverbose\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 482\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_dates\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_dates\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 483\u001b[0m \u001b[43m \u001b[49m\u001b[43mdate_parser\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdate_parser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 484\u001b[0m \u001b[43m \u001b[49m\u001b[43mthousands\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mthousands\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 485\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecimal\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecimal\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 486\u001b[0m \u001b[43m \u001b[49m\u001b[43mcomment\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcomment\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 487\u001b[0m \u001b[43m \u001b[49m\u001b[43mskipfooter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskipfooter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 488\u001b[0m \u001b[43m \u001b[49m\u001b[43mconvert_float\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconvert_float\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 489\u001b[0m \u001b[43m \u001b[49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 490\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 491\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m 492\u001b[0m \u001b[38;5;66;03m# make sure to close opened file handles\u001b[39;00m\n\u001b[1;32m 493\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m should_close:\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/excel/_base.py:1458\u001b[0m, in \u001b[0;36mExcelFile.parse\u001b[0;34m(self, sheet_name, header, names, index_col, usecols, squeeze, converters, true_values, false_values, skiprows, nrows, na_values, parse_dates, date_parser, thousands, comment, skipfooter, convert_float, mangle_dupe_cols, **kwds)\u001b[0m\n\u001b[1;32m 1424\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparse\u001b[39m(\n\u001b[1;32m 1425\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 1426\u001b[0m sheet_name: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mint\u001b[39m \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mlist\u001b[39m[\u001b[38;5;28mint\u001b[39m] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mlist\u001b[39m[\u001b[38;5;28mstr\u001b[39m] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1445\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwds,\n\u001b[1;32m 1446\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m DataFrame \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, DataFrame] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mint\u001b[39m, DataFrame]:\n\u001b[1;32m 1447\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 1448\u001b[0m \u001b[38;5;124;03m Parse specified sheet(s) into a DataFrame.\u001b[39;00m\n\u001b[1;32m 1449\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1456\u001b[0m \u001b[38;5;124;03m DataFrame from the passed in Excel file.\u001b[39;00m\n\u001b[1;32m 1457\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m-> 1458\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_reader\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1459\u001b[0m \u001b[43m \u001b[49m\u001b[43msheet_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msheet_name\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1460\u001b[0m \u001b[43m \u001b[49m\u001b[43mheader\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheader\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1461\u001b[0m \u001b[43m \u001b[49m\u001b[43mnames\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnames\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1462\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex_col\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindex_col\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1463\u001b[0m \u001b[43m \u001b[49m\u001b[43musecols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43musecols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1464\u001b[0m \u001b[43m \u001b[49m\u001b[43msqueeze\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msqueeze\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1465\u001b[0m \u001b[43m \u001b[49m\u001b[43mconverters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconverters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1466\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrue_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrue_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1467\u001b[0m \u001b[43m \u001b[49m\u001b[43mfalse_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfalse_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1468\u001b[0m \u001b[43m \u001b[49m\u001b[43mskiprows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskiprows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1469\u001b[0m \u001b[43m \u001b[49m\u001b[43mnrows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnrows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1470\u001b[0m \u001b[43m \u001b[49m\u001b[43mna_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mna_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1471\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_dates\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_dates\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1472\u001b[0m \u001b[43m \u001b[49m\u001b[43mdate_parser\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdate_parser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1473\u001b[0m \u001b[43m \u001b[49m\u001b[43mthousands\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mthousands\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1474\u001b[0m \u001b[43m \u001b[49m\u001b[43mcomment\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcomment\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1475\u001b[0m \u001b[43m \u001b[49m\u001b[43mskipfooter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskipfooter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1476\u001b[0m \u001b[43m \u001b[49m\u001b[43mconvert_float\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconvert_float\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1477\u001b[0m \u001b[43m \u001b[49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1478\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1479\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/excel/_base.py:715\u001b[0m, in \u001b[0;36mBaseExcelReader.parse\u001b[0;34m(self, sheet_name, header, names, index_col, usecols, squeeze, dtype, true_values, false_values, skiprows, nrows, na_values, verbose, parse_dates, date_parser, thousands, decimal, comment, skipfooter, convert_float, mangle_dupe_cols, **kwds)\u001b[0m\n\u001b[1;32m 713\u001b[0m \u001b[38;5;66;03m# GH 12292 : error when read one empty column from excel file\u001b[39;00m\n\u001b[1;32m 714\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 715\u001b[0m parser \u001b[38;5;241m=\u001b[39m \u001b[43mTextParser\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 716\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 717\u001b[0m \u001b[43m \u001b[49m\u001b[43mnames\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnames\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 718\u001b[0m \u001b[43m \u001b[49m\u001b[43mheader\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheader\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 719\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex_col\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindex_col\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 720\u001b[0m \u001b[43m \u001b[49m\u001b[43mhas_index_names\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhas_index_names\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 721\u001b[0m \u001b[43m \u001b[49m\u001b[43msqueeze\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msqueeze\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 722\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 723\u001b[0m \u001b[43m \u001b[49m\u001b[43mtrue_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtrue_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 724\u001b[0m \u001b[43m \u001b[49m\u001b[43mfalse_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mfalse_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 725\u001b[0m \u001b[43m \u001b[49m\u001b[43mskiprows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskiprows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 726\u001b[0m \u001b[43m \u001b[49m\u001b[43mnrows\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnrows\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 727\u001b[0m \u001b[43m \u001b[49m\u001b[43mna_values\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mna_values\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 728\u001b[0m \u001b[43m \u001b[49m\u001b[43mskip_blank_lines\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# GH 39808\u001b[39;49;00m\n\u001b[1;32m 729\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_dates\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_dates\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 730\u001b[0m \u001b[43m \u001b[49m\u001b[43mdate_parser\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdate_parser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 731\u001b[0m \u001b[43m \u001b[49m\u001b[43mthousands\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mthousands\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 732\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecimal\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecimal\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 733\u001b[0m \u001b[43m \u001b[49m\u001b[43mcomment\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcomment\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 734\u001b[0m \u001b[43m \u001b[49m\u001b[43mskipfooter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mskipfooter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 735\u001b[0m \u001b[43m \u001b[49m\u001b[43musecols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43musecols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 736\u001b[0m \u001b[43m \u001b[49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmangle_dupe_cols\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 737\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 738\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 740\u001b[0m output[asheetname] \u001b[38;5;241m=\u001b[39m parser\u001b[38;5;241m.\u001b[39mread(nrows\u001b[38;5;241m=\u001b[39mnrows)\n\u001b[1;32m 742\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m squeeze \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(output[asheetname], DataFrame):\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1350\u001b[0m, in \u001b[0;36mTextParser\u001b[0;34m(*args, **kwds)\u001b[0m\n\u001b[1;32m 1294\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 1295\u001b[0m \u001b[38;5;124;03mConverts lists of lists/tuples into DataFrames with proper type inference\u001b[39;00m\n\u001b[1;32m 1296\u001b[0m \u001b[38;5;124;03mand optional (e.g. string to datetime) conversion. Also enables iterating\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1347\u001b[0m \u001b[38;5;124;03m .. versionchanged:: 1.2\u001b[39;00m\n\u001b[1;32m 1348\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 1349\u001b[0m kwds[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mengine\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpython\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1350\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mTextFileReader\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwds\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/parsers/readers.py:933\u001b[0m, in \u001b[0;36mTextFileReader.__init__\u001b[0;34m(self, f, engine, **kwds)\u001b[0m\n\u001b[1;32m 930\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhas_index_names\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m kwds[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhas_index_names\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 932\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles: IOHandles \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 933\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_engine \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_make_engine\u001b[49m\u001b[43m(\u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mengine\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1235\u001b[0m, in \u001b[0;36mTextFileReader._make_engine\u001b[0;34m(self, f, engine)\u001b[0m\n\u001b[1;32m 1232\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(msg)\n\u001b[1;32m 1234\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1235\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmapping\u001b[49m\u001b[43m[\u001b[49m\u001b[43mengine\u001b[49m\u001b[43m]\u001b[49m\u001b[43m(\u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1236\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[1;32m 1237\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandles \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/parsers/python_parser.py:148\u001b[0m, in \u001b[0;36mPythonParser.__init__\u001b[0;34m(self, f, **kwds)\u001b[0m\n\u001b[1;32m 145\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_col_indices \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 146\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_col_indices \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(\u001b[38;5;28mrange\u001b[39m(\u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns)))\n\u001b[0;32m--> 148\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_parse_date_cols \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_parse_dates_presence\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 149\u001b[0m no_thousands_columns: \u001b[38;5;28mset\u001b[39m[\u001b[38;5;28mint\u001b[39m] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 150\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_dates:\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/io/parsers/base_parser.py:228\u001b[0m, in \u001b[0;36mParserBase._validate_parse_dates_presence\u001b[0;34m(self, columns)\u001b[0m\n\u001b[1;32m 218\u001b[0m missing_cols \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\n\u001b[1;32m 219\u001b[0m \u001b[38;5;28msorted\u001b[39m(\n\u001b[1;32m 220\u001b[0m {\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 225\u001b[0m )\n\u001b[1;32m 226\u001b[0m )\n\u001b[1;32m 227\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m missing_cols:\n\u001b[0;32m--> 228\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 229\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMissing column provided to \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mparse_dates\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m: \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmissing_cols\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 230\u001b[0m )\n\u001b[1;32m 231\u001b[0m \u001b[38;5;66;03m# Convert positions to actual column names\u001b[39;00m\n\u001b[1;32m 232\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m [\n\u001b[1;32m 233\u001b[0m col \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28misinstance\u001b[39m(col, \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m col \u001b[38;5;129;01min\u001b[39;00m columns) \u001b[38;5;28;01melse\u001b[39;00m columns[col]\n\u001b[1;32m 234\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m col \u001b[38;5;129;01min\u001b[39;00m cols_needed\n\u001b[1;32m 235\u001b[0m ]\n", + "\u001b[0;31mValueError\u001b[0m: Missing column provided to 'parse_dates': 'Data di nascita, Data fine contratto\n(o data fine assistenza se diversa) *, Data inizio contratto (o data inizio assistenza se diversa)'" + ] + } + ], + "source": [ + "df = pd.read_excel(fn,parse_dates = ['Data di nascita','Data fine contratto\\n(o data fine assistenza se diversa) *','Data inizio contratto (o data inizio assistenza se diversa)'], header=8)" + ] + }, + { + "cell_type": "code", + "execution_count": 793, + "id": "04d0dd52", + "metadata": {}, + "outputs": [], + "source": [ + "df['Numero \\nprogressivo'] = pd.to_numeric(df['Numero \\nprogressivo'],errors='coerce')" + ] + }, + { + "cell_type": "code", + "execution_count": 794, + "id": "535b67dd", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df['Numero \\nprogressivo'].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 795, + "id": "2ceb5385", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 796, + "id": "b4917c5c", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,'Comune',gemeinde[3])" + ] + }, + { + "cell_type": "code", + "execution_count": 797, + "id": "3a56fe8f", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,'Ente',t)" + ] + }, + { + "cell_type": "code", + "execution_count": 798, + "id": "b77a4d81", + "metadata": {}, + "outputs": [], + "source": [ + "c =df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 860, + "id": "c922325f", + "metadata": {}, + "outputs": [], + "source": [ + "giorni = (\n", + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"]\n", + " - df[\"Data di nascita\"]\n", + " ).dt.days < 90" + ] + }, + { + "cell_type": "code", + "execution_count": 862, + "id": "7bf86007", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"errAgeChild\"] = np.nan\n", + "df[\"errAgeChild\"] = df[\"errAgeChild\"].astype(\"boolean\")" + ] + }, + { + "cell_type": "code", + "execution_count": 887, + "id": "5f9fcc35", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020'],\n", + " dtype='object')" + ] + }, + "execution_count": 887, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 876, + "id": "31b51072", + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Length mismatch: Expected axis has 17 elements, new values have 4 elements", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [876]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m df\u001b[38;5;241m.\u001b[39mcolumns \u001b[38;5;241m=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnew_col1\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnew_col2\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnew_col3\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnew_col4\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/core/generic.py:5588\u001b[0m, in \u001b[0;36mNDFrame.__setattr__\u001b[0;34m(self, name, value)\u001b[0m\n\u001b[1;32m 5586\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 5587\u001b[0m \u001b[38;5;28mobject\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__getattribute__\u001b[39m(\u001b[38;5;28mself\u001b[39m, name)\n\u001b[0;32m-> 5588\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mobject\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__setattr__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 5589\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mAttributeError\u001b[39;00m:\n\u001b[1;32m 5590\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/_libs/properties.pyx:70\u001b[0m, in \u001b[0;36mpandas._libs.properties.AxisProperty.__set__\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/core/generic.py:769\u001b[0m, in \u001b[0;36mNDFrame._set_axis\u001b[0;34m(self, axis, labels)\u001b[0m\n\u001b[1;32m 767\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_set_axis\u001b[39m(\u001b[38;5;28mself\u001b[39m, axis: \u001b[38;5;28mint\u001b[39m, labels: Index) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 768\u001b[0m labels \u001b[38;5;241m=\u001b[39m ensure_index(labels)\n\u001b[0;32m--> 769\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_mgr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mset_axis\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlabels\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 770\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_clear_item_cache()\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/core/internals/managers.py:214\u001b[0m, in \u001b[0;36mBaseBlockManager.set_axis\u001b[0;34m(self, axis, new_labels)\u001b[0m\n\u001b[1;32m 212\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mset_axis\u001b[39m(\u001b[38;5;28mself\u001b[39m, axis: \u001b[38;5;28mint\u001b[39m, new_labels: Index) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 213\u001b[0m \u001b[38;5;66;03m# Caller is responsible for ensuring we have an Index object.\u001b[39;00m\n\u001b[0;32m--> 214\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_validate_set_axis\u001b[49m\u001b[43m(\u001b[49m\u001b[43maxis\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnew_labels\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 215\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maxes[axis] \u001b[38;5;241m=\u001b[39m new_labels\n", + "File \u001b[0;32m~/.local/share/virtualenvs/max-8kS0DQDt/lib/python3.8/site-packages/pandas/core/internals/base.py:69\u001b[0m, in \u001b[0;36mDataManager._validate_set_axis\u001b[0;34m(self, axis, new_labels)\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[38;5;28;01mpass\u001b[39;00m\n\u001b[1;32m 68\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m new_len \u001b[38;5;241m!=\u001b[39m old_len:\n\u001b[0;32m---> 69\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 70\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mLength mismatch: Expected axis has \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mold_len\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m elements, new \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 71\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mvalues have \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mnew_len\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m elements\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 72\u001b[0m )\n", + "\u001b[0;31mValueError\u001b[0m: Length mismatch: Expected axis has 17 elements, new values have 4 elements" + ] + } + ], + "source": [ + "df.columns = ['new_col1', 'new_col2', 'new_col3', 'new_col4']" + ] + }, + { + "cell_type": "code", + "execution_count": 874, + "id": "0111f39e", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[giorni,'errAgeChild'] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 875, + "id": "587bbd0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoEnteComuneCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020errCodFisc1errAgeChild
01.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoAZZALI LIAM2019-01-28ZZLLMI18C28A952JCARUSO MARIABOLZANO2019-02-182020-04-30319.00398.75NaN464.01181.75<NA>True
12.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoBAHTIJAR RASIM2018-12-04BHTRSM18T04F132CMILITARU ROXANABOLZANO2020-02-102020-08-21108.50132.00NaN96.0336.50<NA><NA>
23.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoBARAGONA LUCA2017-08-21BRGLCU17M21A952WLOVATO DEBORAHBOLZANO2019-09-162022-04-3097.75140.25NaNNaN238.00<NA><NA>
34.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoBAH MAMADOU ADAMA2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192020-12-31144.0032.00NaNNaN176.00<NA><NA>
45.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoTUCCIO GABRIEL2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2021-06-082021-02-27559.7534.00NaNNaN593.75<NA><NA>
......................................................
6462.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoTRINCO ANITA2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-3120.000.00NaNNaN20.00<NA><NA>
6563.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoWEGLEITER ENEAS2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132021-08-31559.2557.75132.25NaN749.25<NA><NA>
6664.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoVAFADAR DARIO2017-06-01VFDDRA17H01A952KMOSSA DANIELABOLZANO2019-11-112020-02-15111.500.00NaNNaN111.50<NA><NA>
6765.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoMANGIALAIO OLIVER2017-12-02MNGLVR17T02B220PMATTEOTTI GIACOMOBOLZANO2018-08-062020-09-04543.00370.50NaN34.0947.50<NA><NA>
6866.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoRINDONE FILIPPO TOMMASO2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-26432.0044.0027.50NaN503.50<NA><NA>
\n", + "

69 rows × 17 columns

\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Ente Comune \\\n", + "0 1.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "1 2.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "2 3.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "3 4.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "4 5.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + ".. ... ... ... \n", + "64 62.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "65 63.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "66 64.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "67 65.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "68 66.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "\n", + " Cognome e nome bambino Data di nascita Codice fiscale \\\n", + "0 AZZALI LIAM 2019-01-28 ZZLLMI18C28A952J \n", + "1 BAHTIJAR RASIM 2018-12-04 BHTRSM18T04F132C \n", + "2 BARAGONA LUCA 2017-08-21 BRGLCU17M21A952W \n", + "3 BAH MAMADOU ADAMA 2019-03-22 BHMDMA19C62A952Y \n", + "4 TUCCIO GABRIEL 2019-03-23 TCCGRL19C23A952W \n", + ".. ... ... ... \n", + "64 TRINCO ANITA 2020-05-30 TRNNTA20E70A952B \n", + "65 WEGLEITER ENEAS 2018-10-22 WGLNSE18R22B160O \n", + "66 VAFADAR DARIO 2017-06-01 VFDDRA17H01A952K \n", + "67 MANGIALAIO OLIVER 2017-12-02 MNGLVR17T02B220P \n", + "68 RINDONE FILIPPO TOMMASO 2019-10-31 RNDFPP19R31A952Y \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 CARUSO MARIA \n", + "1 MILITARU ROXANA \n", + "2 LOVATO DEBORAH \n", + "3 LOVATO DEBORAH \n", + "4 MARTINELLO SILVIA \n", + ".. ... \n", + "64 CARUSO MARIA \n", + "65 MOSSA DANIELA \n", + "66 MOSSA DANIELA \n", + "67 MATTEOTTI GIACOMO \n", + "68 CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 BOLZANO \n", + "1 BOLZANO \n", + "2 BOLZANO \n", + "3 BOLZANO \n", + "4 BOLZANO \n", + ".. ... \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "66 BOLZANO \n", + "67 BOLZANO \n", + "68 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 2019-02-18 \n", + "1 2020-02-10 \n", + "2 2019-09-16 \n", + "3 2020-10-19 \n", + "4 2021-06-08 \n", + ".. ... \n", + "64 2020-12-28 \n", + "65 2020-07-13 \n", + "66 2019-11-11 \n", + "67 2018-08-06 \n", + "68 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 2020-04-30 \n", + "1 2020-08-21 \n", + "2 2022-04-30 \n", + "3 2020-12-31 \n", + "4 2021-02-27 \n", + ".. ... \n", + "64 2023-08-31 \n", + "65 2021-08-31 \n", + "66 2020-02-15 \n", + "67 2020-09-04 \n", + "68 2022-08-26 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 319.00 \n", + "1 108.50 \n", + "2 97.75 \n", + "3 144.00 \n", + "4 559.75 \n", + ".. ... \n", + "64 20.00 \n", + "65 559.25 \n", + "66 111.50 \n", + "67 543.00 \n", + "68 432.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "0 398.75 \n", + "1 132.00 \n", + "2 140.25 \n", + "3 32.00 \n", + "4 34.00 \n", + ".. ... \n", + "64 0.00 \n", + "65 57.75 \n", + "66 0.00 \n", + "67 370.50 \n", + "68 44.00 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "64 NaN \n", + "65 132.25 \n", + "66 NaN \n", + "67 NaN \n", + "68 27.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "0 464.0 \n", + "1 96.0 \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "64 NaN \n", + "65 NaN \n", + "66 NaN \n", + "67 34.0 \n", + "68 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 errCodFisc1 errAgeChild \n", + "0 1181.75 True \n", + "1 336.50 \n", + "2 238.00 \n", + "3 176.00 \n", + "4 593.75 \n", + ".. ... ... ... \n", + "64 20.00 \n", + "65 749.25 \n", + "66 111.50 \n", + "67 947.50 \n", + "68 503.50 \n", + "\n", + "[69 rows x 17 columns]" + ] + }, + "execution_count": 875, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 859, + "id": "23f37fce", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoEnteComuneCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)Ore totali rendicontate per il 2020errCodFisc1
4341.0Soc. Coop. Casa Bimbo Tagesmutter OnlusBolzanoSCHILLACI ANTONINO2017-01-23SCHNN17A23A952VCARUSO MARIABOLZANO2018-08-272020-08-31532.5315.0NaNNaN847.5True
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Ente Comune \\\n", + "43 41.0 Soc. Coop. Casa Bimbo Tagesmutter Onlus Bolzano \n", + "\n", + " Cognome e nome bambino Data di nascita Codice fiscale \\\n", + "43 SCHILLACI ANTONINO 2017-01-23 SCHNN17A23A952V \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "43 CARUSO MARIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "43 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "43 2018-08-27 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "43 2020-08-31 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "43 532.5 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020 \\\n", + "43 315.0 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020 \\\n", + "43 NaN \n", + "\n", + " Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo) \\\n", + "43 NaN \n", + "\n", + " Ore totali rendicontate per il 2020 errCodFisc1 \n", + "43 847.5 True " + ] + }, + "execution_count": 859, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 1007, + "id": "4afdeb3d", + "metadata": {}, + "outputs": [], + "source": [ + "errordict = {'errCodFisc1': \"errore codice fiscale\", \"errCodFisc2\": \"errore codice fiscale 2\"}" + ] + }, + { + "cell_type": "code", + "execution_count": 1009, + "id": "742fd092", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'errore codice fiscale'" + ] + }, + "execution_count": 1009, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "errordict[\"errCodFisc1\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 1011, + "id": "dcea722c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "errCodFisc1\n", + "errCodFisc2\n" + ] + } + ], + "source": [ + "for e in errordict.keys():\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 1012, + "id": "9a0ed635", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "for a in range(4):\n", + " print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 1016, + "id": "1142fa07", + "metadata": {}, + "outputs": [], + "source": [ + "d = pd.to_datetime(\"01.03.2017\", infer_datetime_format=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 1017, + "id": "d12af5fd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Timestamp('2017-01-03 00:00:00')" + ] + }, + "execution_count": 1017, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d" + ] + }, + { + "cell_type": "code", + "execution_count": 1020, + "id": "d6ee5cd1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Timestamp('2017-03-01 00:00:00')" + ] + }, + "execution_count": 1020, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.to_datetime(\"01.03.2017\", format='%d.%m.%Y')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ecf3e24", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled1.ipynb b/pages/Jupyter/Untitled1.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/Untitled1.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled2.ipynb b/pages/Jupyter/Untitled2.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/Untitled2.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled3.ipynb b/pages/Jupyter/Untitled3.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..5d4f585822f6133b974391d84a8729cb6c6182b4 --- /dev/null +++ b/pages/Jupyter/Untitled3.ipynb @@ -0,0 +1,305 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "6c8c6238", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "12f86ceb", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame(\n", + "\n", + " {\"AAA\": [4, 5, 6, 7], \"BBB\": [10, 20, 30, 40], \"CCC\": [100, 50, -30, -50]}\n", + "\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "43a66a65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AAABBBCCC
0410100
152050
2630-30
3740-50
\n", + "
" + ], + "text/plain": [ + " AAA BBB CCC\n", + "0 4 10 100\n", + "1 5 20 50\n", + "2 6 30 -30\n", + "3 7 40 -50" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "f39b8095", + "metadata": {}, + "outputs": [], + "source": [ + "df_mask = pd.DataFrame(\n", + "\n", + " {\"AAA\": [True] * 4, \"BBB\": [False] * 4, \"CCC\": [True, False] * 2}\n", + "\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8ba9a516", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AAABBBCCC
0TrueFalseTrue
1TrueFalseFalse
2TrueFalseTrue
3TrueFalseFalse
\n", + "
" + ], + "text/plain": [ + " AAA BBB CCC\n", + "0 True False True\n", + "1 True False False\n", + "2 True False True\n", + "3 True False False" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_mask" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "b4f5d339", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
AAABBBCCC
0-100010-1000
1-10002050
2-100030-1000
3-100040-50
\n", + "
" + ], + "text/plain": [ + " AAA BBB CCC\n", + "0 -1000 10 -1000\n", + "1 -1000 20 50\n", + "2 -1000 30 -1000\n", + "3 -1000 40 -50" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.where(~df_mask, -1000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08b72afc", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled4.ipynb b/pages/Jupyter/Untitled4.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/Untitled4.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled5.ipynb b/pages/Jupyter/Untitled5.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..103a6973e887a99c28f3355fc4545c391518b334 --- /dev/null +++ b/pages/Jupyter/Untitled5.ipynb @@ -0,0 +1,8213 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 17, + "id": "c9b5a057", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "455af2bb", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(\"storico.xlsx\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "3b7fb1ad", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'filename', 'Cognome e nome bambino', 'Ente', 'Comune',\n", + " 'Data di nascita', 'Codice fiscale',\n", + " 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'massimo543',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'errCodFisc1', 'errCodFisc2',\n", + " 'errAgeChild', 'errInizioMinoreFine', 'errErrorePresenza',\n", + " 'errErroreDati543', 'errFineAssistenzaMax4Anni', 'errKindergarten_1',\n", + " 'errKindergarten_2', 'errErroreFinanziamentoCompensativo',\n", + " 'errErroreFinanziamentoCompensativo2', 'errErroreCovid',\n", + " 'errErroreCovid2', 'errErroreCovid3', 'errErroreCovid4',\n", + " 'errFehlerEingewöhnung', 'errFehlerEingewöhnung543Lockdown',\n", + " 'errFehlerEingewöhnung543Notbetreuung',\n", + " 'errGesamtstundenVertragszeitraum', 'errSuperatoOreMassime1920',\n", + " 'errBambinoInPiuComuni', 'errPresentiAnnotazioni',\n", + " 'errOreRendicontateZero', 'gg1', 'gg2', 'gg3', 'inizioNorm',\n", + " 'fineNorm'],\n", + " dtype='object')" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "6d56d37b", + "metadata": {}, + "outputs": [], + "source": [ + "e = df[\"Ente\"] == \"Sozialgenossenschaft Mit Bäuerinnen Lernen Wachsen Leben\"" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "6a049b4f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0filenameCognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)...errGesamtstundenVertragszeitraumerrSuperatoOreMassime1920errBambinoInPiuComunierrPresentiAnnotazionierrOreRendicontateZerogg1gg2gg3inizioNormfineNorm
09Erklärung Gemeinden Jahr 2020 Ahrntal.xlsxAjardi JosefSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Ahrntal2019-10-02JRDJSF19R02B220YKirchler JudithSt. Peter In Ahrntal2020-02-24...NaNNaNNaNNaNNaN74802020-02-242020-12-31
110Erklärung Gemeinden Jahr 2020 Ahrntal.xlsxEder Nicolas AdeleSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Ahrntal2019-01-06DRNDLA19A46Z131EKirchler ClaudiaSt. Jakob in Ahrntal2020-02-12...NaNNaNNaNNaNNaN0002020-02-122020-05-06
219Erklärung Gemeinden Jahr 2020 Ahrntal.xlsxLechner LisaSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Ahrntal2018-06-09LCHLSI18H49B220JKirchler ClaudiaSt. Jakob in Ahrntal2019-12-02...NaNNaNNaNNaNNaN0002020-01-012020-05-06
331Erklärung Gemeinden Jahr 2020 Ahrntal.xlsxRuiu NinaSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Ahrntal2017-03-25RUINNI17C65B220YKirchler IrmgardAhrntal2018-03-01...NaNNaNNaNNaNNaN74002020-01-012020-10-13
98Erklärung Gemeinden Jahr 2020 Auer.xlsxBilli LorenzoSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Auer2020-02-12BLLLNZ20B12A952JHuber MelanieMargreid2020-11-09...NaNNaNNaNNaNNaN0802020-11-092020-12-31
\n", + "

5 rows × 46 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 filename \\\n", + "0 9 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "2 19 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "3 31 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "9 8 Erklärung Gemeinden Jahr 2020 Auer.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "0 Ajardi Josef Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "2 Lechner Lisa Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "3 Ruiu Nina Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "9 Billi Lorenzo Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "0 Ahrntal 2019-10-02 JRDJSF19R02B220Y \n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "2 Ahrntal 2018-06-09 LCHLSI18H49B220J \n", + "3 Ahrntal 2017-03-25 RUINNI17C65B220Y \n", + "9 Auer 2020-02-12 BLLLNZ20B12A952J \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "0 Kirchler Judith \n", + "1 Kirchler Claudia \n", + "2 Kirchler Claudia \n", + "3 Kirchler Irmgard \n", + "9 Huber Melanie \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 St. Peter In Ahrntal \n", + "1 St. Jakob in Ahrntal \n", + "2 St. Jakob in Ahrntal \n", + "3 Ahrntal \n", + "9 Margreid \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "0 2020-02-24 ... \n", + "1 2020-02-12 ... \n", + "2 2019-12-02 ... \n", + "3 2018-03-01 ... \n", + "9 2020-11-09 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "9 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "0 NaN NaN NaN 74 \n", + "1 NaN NaN NaN 0 \n", + "2 NaN NaN NaN 0 \n", + "3 NaN NaN NaN 74 \n", + "9 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "0 8 0 2020-02-24 2020-12-31 \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "2 0 0 2020-01-01 2020-05-06 \n", + "3 0 0 2020-01-01 2020-10-13 \n", + "9 8 0 2020-11-09 2020-12-31 \n", + "\n", + "[5 rows x 46 columns]" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[e]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a0bd5287", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1317" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Codice fiscale\"].nunique()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "2ed1306d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ajardi Josef\n", + "Eder Nicolas Adele\n", + "Lechner Lisa\n", + "Ruiu Nina\n", + "Billi Lorenzo\n" + ] + } + ], + "source": [ + "for n in df[\"Cognome e nome bambino\"][df[\"Ente\"] == \"Sozialgenossenschaft Mit Bäuerinnen Lernen Wachsen Leben\"]:\n", + " print(n)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "3827d038", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 Ajardi Josef\n", + "1 Eder Nicolas Adele\n", + "2 Lechner Lisa\n", + "3 Ruiu Nina\n", + "9 Billi Lorenzo\n", + "Name: Cognome e nome bambino, dtype: object" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Cognome e nome bambino\"][df[\"Ente\"] == \"Sozialgenossenschaft Mit Bäuerinnen Lernen Wachsen Leben\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "1a488c53", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n", + " Unnamed: 0 filename \\\n", + "1 10 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "\n", + " Cognome e nome bambino Ente \\\n", + "1 Eder Nicolas Adele Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... \n", + "\n", + " Comune Data di nascita Codice fiscale \\\n", + "1 Ahrntal 2019-01-06 DRNDLA19A46Z131E \n", + "\n", + " Assistente domiciliare all'infanzia \\\n", + "1 Kirchler Claudia \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "1 St. Jakob in Ahrntal \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "1 2020-02-12 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "1 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero gg1 \\\n", + "1 NaN NaN NaN 0 \n", + "\n", + " gg2 gg3 inizioNorm fineNorm \n", + "1 0 0 2020-02-12 2020-05-06 \n", + "\n", + "[1 rows x 46 columns]\n" + ] + } + ], + "source": [ + "for i in df.index:\n", + " print(df.iloc[[1]])" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "d7363ec7", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'index' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [34]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m df[\u001b[43mindex\u001b[49m \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m]\n", + "\u001b[0;31mNameError\u001b[0m: name 'index' is not defined" + ] + } + ], + "source": [ + "df[index == 1]" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "dd5aba3e", + "metadata": {}, + "outputs": [], + "source": [ + "n = df.iloc[[1]][\"Cognome e nome bambino\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "2f268c5b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'EDER NICOLAS ADELE'" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "n.values[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "id": "08b976ed", + "metadata": {}, + "outputs": [], + "source": [ + "condizione = (df.groupby(\"Ente\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "8dbbb26f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 2283.25\n", + "1 2283.25\n", + "2 2283.25\n", + "3 2283.25\n", + "4 112899.50\n", + " ... \n", + "242 112899.50\n", + "243 112899.50\n", + "244 112899.50\n", + "245 112899.50\n", + "246 112899.50\n", + "Name: Ore totali rendicontate per il 2020, Length: 247, dtype: float64" + ] + }, + "execution_count": 84, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "condizione" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "6b84073b", + "metadata": {}, + "outputs": [], + "source": [ + "df_s = df.groupby(\"Ente\").sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "96bc877c", + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'Ente'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py:3361\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3360\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 3361\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3362\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/index.pyx:76\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/_libs/index.pyx:108\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:5198\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:5206\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", + "\u001b[0;31mKeyError\u001b[0m: 'Ente'", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [91]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m df_s[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mente\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mdf_s\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mEnte\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/frame.py:3458\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 3456\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m 3457\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[0;32m-> 3458\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3459\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[1;32m 3460\u001b[0m indexer \u001b[38;5;241m=\u001b[39m [indexer]\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py:3363\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 3361\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_engine\u001b[38;5;241m.\u001b[39mget_loc(casted_key)\n\u001b[1;32m 3362\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n\u001b[0;32m-> 3363\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m 3365\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_scalar(key) \u001b[38;5;129;01mand\u001b[39;00m isna(key) \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhasnans:\n\u001b[1;32m 3366\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key)\n", + "\u001b[0;31mKeyError\u001b[0m: 'Ente'" + ] + } + ], + "source": [ + "df_s[\"ente\"] = df_s[\"Ente\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "id": "7337f7df", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'massimo543',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'errCodFisc1', 'errCodFisc2',\n", + " 'errAgeChild', 'errInizioMinoreFine', 'errErrorePresenza',\n", + " 'errErroreDati543', 'errFineAssistenzaMax4Anni', 'errKindergarten_1',\n", + " 'errKindergarten_2', 'errErroreFinanziamentoCompensativo',\n", + " 'errErroreFinanziamentoCompensativo2', 'errErroreCovid',\n", + " 'errErroreCovid2', 'errErroreCovid3', 'errErroreCovid4',\n", + " 'errFehlerEingewöhnung', 'errFehlerEingewöhnung543Lockdown',\n", + " 'errFehlerEingewöhnung543Notbetreuung',\n", + " 'errGesamtstundenVertragszeitraum', 'errSuperatoOreMassime1920',\n", + " 'errBambinoInPiuComuni', 'errPresentiAnnotazioni',\n", + " 'errOreRendicontateZero', 'gg1', 'gg2', 'gg3'],\n", + " dtype='object')" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_s.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "22946522", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'df_S' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [100]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf_S\u001b[49m\n", + "\u001b[0;31mNameError\u001b[0m: name 'df_S' is not defined" + ] + } + ], + "source": [ + "df_S" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "id": "ca9c3f62", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'massimo543',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'errCodFisc1', 'errCodFisc2',\n", + " 'errAgeChild', 'errInizioMinoreFine', 'errErrorePresenza',\n", + " 'errErroreDati543', 'errFineAssistenzaMax4Anni', 'errKindergarten_1',\n", + " 'errKindergarten_2', 'errErroreFinanziamentoCompensativo',\n", + " 'errErroreFinanziamentoCompensativo2', 'errErroreCovid',\n", + " 'errErroreCovid2', 'errErroreCovid3', 'errErroreCovid4',\n", + " 'errFehlerEingewöhnung', 'errFehlerEingewöhnung543Lockdown',\n", + " 'errFehlerEingewöhnung543Notbetreuung',\n", + " 'errGesamtstundenVertragszeitraum', 'errSuperatoOreMassime1920',\n", + " 'errBambinoInPiuComuni', 'errPresentiAnnotazioni',\n", + " 'errOreRendicontateZero', 'gg1', 'gg2', 'gg3'],\n", + " dtype='object')" + ] + }, + "execution_count": 102, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_s.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "id": "960655a6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Unnamed: 0', 'GiorniAssistenzaAnnoRiferimento',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020',\n", + " 'massimo543',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 733/2020',\n", + " 'Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)',\n", + " 'Ore totali rendicontate per il 2020', 'errCodFisc1', 'errCodFisc2',\n", + " 'errAgeChild', 'errInizioMinoreFine', 'errErrorePresenza',\n", + " 'errErroreDati543', 'errFineAssistenzaMax4Anni', 'errKindergarten_1',\n", + " 'errKindergarten_2', 'errErroreFinanziamentoCompensativo',\n", + " 'errErroreFinanziamentoCompensativo2', 'errErroreCovid',\n", + " 'errErroreCovid2', 'errErroreCovid3', 'errErroreCovid4',\n", + " 'errFehlerEingewöhnung', 'errFehlerEingewöhnung543Lockdown',\n", + " 'errFehlerEingewöhnung543Notbetreuung',\n", + " 'errGesamtstundenVertragszeitraum', 'errSuperatoOreMassime1920',\n", + " 'errBambinoInPiuComuni', 'errPresentiAnnotazioni',\n", + " 'errOreRendicontateZero', 'gg1', 'gg2', 'gg3'],\n", + " dtype='object')" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_s.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "636ad627", + "metadata": {}, + "outputs": [], + "source": [ + "dff = df.groupby(\"Ente\", as_index=False).sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "id": "dd754933", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 Sozialgenossenschaft Mit Bäuerinnen Lernen Wac...\n", + "1 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac...\n", + "Name: Ente, dtype: object" + ] + }, + "execution_count": 118, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dff[\"Ente\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "id": "449e387a", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'DataFrame' object has no attribute 'Ente'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [114]\u001b[0m, in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdff\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mEnte\u001b[49m\n", + "File \u001b[0;32m~/.local/lib/python3.8/site-packages/pandas/core/generic.py:5487\u001b[0m, in \u001b[0;36mNDFrame.__getattr__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 5480\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[1;32m 5481\u001b[0m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_internal_names_set\n\u001b[1;32m 5482\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_metadata\n\u001b[1;32m 5483\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_accessors\n\u001b[1;32m 5484\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_info_axis\u001b[38;5;241m.\u001b[39m_can_hold_identifiers_and_holds_name(name)\n\u001b[1;32m 5485\u001b[0m ):\n\u001b[1;32m 5486\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m[name]\n\u001b[0;32m-> 5487\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mobject\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getattribute__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'DataFrame' object has no attribute 'Ente'" + ] + } + ], + "source": [ + "dff.Ente" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "id": "7b07e7a3", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.sort_values(by=['Cognome e nome bambino'])" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "id": "b8b3b213", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Unnamed: 0filenameCognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)...errGesamtstundenVertragszeitraumerrSuperatoOreMassime1920errBambinoInPiuComunierrPresentiAnnotazionierrOreRendicontateZerogg1gg2gg3inizioNormfineNorm
1528Erklärung Gemeinden Jahr 2020 Partschings.xlsxAbler SophieSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Partschins2016-12-28BLRSPH16T68F132BTappeiner HeidemariePartschins2017-09-01...NaNNaNNaNNaNNaN74002020-01-012020-10-30
1029Erklärung Gemeinden Jahr 2020 Meran.xlsxAgostinetto LeviSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Meran2017-02-06GSTLVE17B06A952VKienzl Martina RosaMeran2017-10-02...NaNNaNNaNNaNNaN74002020-01-012020-08-27
1018Erklärung Gemeinden Jahr 2020 Meran.xlsxAgostinetto MattiSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Meran2020-02-09GSTMTT20B09A952TKienzl Martina RosaMeran2020-10-26...NaNNaNNaNNaNNaN0802020-10-262020-12-31
09Erklärung Gemeinden Jahr 2020 Ahrntal.xlsxAjardi JosefSozialgenossenschaft Mit Bäuerinnen Lernen Wac...Ahrntal2019-10-02JRDJSF19R02B220YKirchler JudithSt. Peter In Ahrntal2020-02-24...NaNNaNNaNNaNNaN74802020-02-242020-12-31
858Erklärung Gemeinden Jahr 2020 Leifers.xlsxAlia AmeliaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Leifers2018-11-21LAIMLA18S61A952SKienzl Karin AnnaLeifers2019-04-15...NaNNaN1.0NaNNaN74822020-01-012020-12-31
..................................................................
19915Erklärung Gemeinden Jahr 2020 Sterzing.xlsxWhitecotton Leopold Harrison *Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Sterzing2018-02-20WHTLLD18B20Z112ZOberstaller AgathePfitsch2019-09-17...NaNNaN1.01.0NaN0002020-01-012020-03-30
1519Erklärung Gemeinden Jahr 2020 Olang.xlsxWinkler PaulaSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Olang2017-10-02WNKPLA17R42B220LOberleiter Maria MagdalenaPercha2019-10-23...NaNNaNNaNNaNNaN74802020-01-012020-12-31
2753Erklärung Gemeinden Jahr 2020 Brixen.xlsxWitcher Noah SebastianSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Brixen2017-03-04WTCNSB17C04B160XTschiggfrei MonikaBrixen2020-01-14...NaNNaNNaNNaNNaN74002020-01-142020-09-25
19015Erklärung Gemeinden Jahr 2020 Schnals.xlsxWoerndle PaulSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Schnals2017-12-13WRNPLA17T13I729ZGraiss LisaSchnals2020-11-02...NaNNaNNaNNaNNaN0822020-11-022020-12-31
21819Erklärung Gemeinden Jahr 2020 Tramin.xlsxZelger SamuelSozialgenossenschaft Mit Bäuerinnen Lernen-Wac...Tramin2018-05-08ZLGSML18E08F132PPeer PetraKurtatsch2020-02-03...NaNNaNNaNNaNNaN0002020-02-032020-05-06
\n", + "

247 rows × 46 columns

\n", + "
" + ], + "text/plain": [ + " Unnamed: 0 filename \\\n", + "152 8 Erklärung Gemeinden Jahr 2020 Partschings.xlsx \n", + "102 9 Erklärung Gemeinden Jahr 2020 Meran.xlsx \n", + "101 8 Erklärung Gemeinden Jahr 2020 Meran.xlsx \n", + "0 9 Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx \n", + "85 8 Erklärung Gemeinden Jahr 2020 Leifers.xlsx \n", + ".. ... ... \n", + "199 15 Erklärung Gemeinden Jahr 2020 Sterzing.xlsx \n", + "151 9 Erklärung Gemeinden Jahr 2020 Olang.xlsx \n", + "27 53 Erklärung Gemeinden Jahr 2020 Brixen.xlsx \n", + "190 15 Erklärung Gemeinden Jahr 2020 Schnals.xlsx \n", + "218 19 Erklärung Gemeinden Jahr 2020 Tramin.xlsx \n", + "\n", + " Cognome e nome bambino \\\n", + "152 Abler Sophie \n", + "102 Agostinetto Levi \n", + "101 Agostinetto Matti \n", + "0 Ajardi Josef \n", + "85 Alia Amelia \n", + ".. ... \n", + "199 Whitecotton Leopold Harrison * \n", + "151 Winkler Paula \n", + "27 Witcher Noah Sebastian \n", + "190 Woerndle Paul \n", + "218 Zelger Samuel \n", + "\n", + " Ente Comune \\\n", + "152 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Partschins \n", + "102 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Meran \n", + "101 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Meran \n", + "0 Sozialgenossenschaft Mit Bäuerinnen Lernen Wac... Ahrntal \n", + "85 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Leifers \n", + ".. ... ... \n", + "199 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Sterzing \n", + "151 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Olang \n", + "27 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Brixen \n", + "190 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Schnals \n", + "218 Sozialgenossenschaft Mit Bäuerinnen Lernen-Wac... Tramin \n", + "\n", + " Data di nascita Codice fiscale Assistente domiciliare all'infanzia \\\n", + "152 2016-12-28 BLRSPH16T68F132B Tappeiner Heidemarie \n", + "102 2017-02-06 GSTLVE17B06A952V Kienzl Martina Rosa \n", + "101 2020-02-09 GSTMTT20B09A952T Kienzl Martina Rosa \n", + "0 2019-10-02 JRDJSF19R02B220Y Kirchler Judith \n", + "85 2018-11-21 LAIMLA18S61A952S Kienzl Karin Anna \n", + ".. ... ... ... \n", + "199 2018-02-20 WHTLLD18B20Z112Z Oberstaller Agathe \n", + "151 2017-10-02 WNKPLA17R42B220L Oberleiter Maria Magdalena \n", + "27 2017-03-04 WTCNSB17C04B160X Tschiggfrei Monika \n", + "190 2017-12-13 WRNPLA17T13I729Z Graiss Lisa \n", + "218 2018-05-08 ZLGSML18E08F132P Peer Petra \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "152 Partschins \n", + "102 Meran \n", + "101 Meran \n", + "0 St. Peter In Ahrntal \n", + "85 Leifers \n", + ".. ... \n", + "199 Pfitsch \n", + "151 Percha \n", + "27 Brixen \n", + "190 Schnals \n", + "218 Kurtatsch \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) ... \\\n", + "152 2017-09-01 ... \n", + "102 2017-10-02 ... \n", + "101 2020-10-26 ... \n", + "0 2020-02-24 ... \n", + "85 2019-04-15 ... \n", + ".. ... ... \n", + "199 2019-09-17 ... \n", + "151 2019-10-23 ... \n", + "27 2020-01-14 ... \n", + "190 2020-11-02 ... \n", + "218 2020-02-03 ... \n", + "\n", + " errGesamtstundenVertragszeitraum errSuperatoOreMassime1920 \\\n", + "152 NaN NaN \n", + "102 NaN NaN \n", + "101 NaN NaN \n", + "0 NaN NaN \n", + "85 NaN NaN \n", + ".. ... ... \n", + "199 NaN NaN \n", + "151 NaN NaN \n", + "27 NaN NaN \n", + "190 NaN NaN \n", + "218 NaN NaN \n", + "\n", + " errBambinoInPiuComuni errPresentiAnnotazioni errOreRendicontateZero \\\n", + "152 NaN NaN NaN \n", + "102 NaN NaN NaN \n", + "101 NaN NaN NaN \n", + "0 NaN NaN NaN \n", + "85 1.0 NaN NaN \n", + ".. ... ... ... \n", + "199 1.0 1.0 NaN \n", + "151 NaN NaN NaN \n", + "27 NaN NaN NaN \n", + "190 NaN NaN NaN \n", + "218 NaN NaN NaN \n", + "\n", + " gg1 gg2 gg3 inizioNorm fineNorm \n", + "152 74 0 0 2020-01-01 2020-10-30 \n", + "102 74 0 0 2020-01-01 2020-08-27 \n", + "101 0 8 0 2020-10-26 2020-12-31 \n", + "0 74 8 0 2020-02-24 2020-12-31 \n", + "85 74 8 2 2020-01-01 2020-12-31 \n", + ".. ... ... ... ... ... \n", + "199 0 0 0 2020-01-01 2020-03-30 \n", + "151 74 8 0 2020-01-01 2020-12-31 \n", + "27 74 0 0 2020-01-14 2020-09-25 \n", + "190 0 8 2 2020-11-02 2020-12-31 \n", + "218 0 0 0 2020-02-03 2020-05-06 \n", + "\n", + "[247 rows x 46 columns]" + ] + }, + "execution_count": 124, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37cf5f00", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled6.ipynb b/pages/Jupyter/Untitled6.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b5fb070739a1e847e53b0a085c7f33242e127f29 --- /dev/null +++ b/pages/Jupyter/Untitled6.ipynb @@ -0,0 +1,1015 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "90de7f88", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 347, + "id": "4a942dee", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"prospetto rendicontazione via combattenti 2019.xlsx\"\n", + "fn2 = \"prospetto rendicontazione via combattenti 2019_bis.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 348, + "id": "f80a9a98", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn2,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 349, + "id": "04e4e835", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n", + "df2 = df2.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df2.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 350, + "id": "adb736ff", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "microstruttura = df.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df.iloc[2]\n", + "ente = ente[1]\n", + "df.insert(0, \"Microstruttura\", microstruttura)\n", + "df.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 351, + "id": "1a3f8af9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Cooperativa sociale Coccinella'" + ] + }, + "execution_count": 351, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ente" + ] + }, + { + "cell_type": "code", + "execution_count": 352, + "id": "ce7eb2d3", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "ente = df2.iloc[2]\n", + "ente = ente[2]\n", + "df2.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 353, + "id": "ed333220", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
0Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
1Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...MicrostrutturaBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaN
2Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...Ente gestoreCooperativa Sociale BabycoopNaNNaNNaNNaN
3Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
4Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxx
5Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...cognomenomeNaNNaNNaNNaN
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "0 Cooperativa Sociale Babycoop \n", + "1 Cooperativa Sociale Babycoop \n", + "2 Cooperativa Sociale Babycoop \n", + "3 Cooperativa Sociale Babycoop \n", + "4 Cooperativa Sociale Babycoop \n", + "5 Cooperativa Sociale Babycoop \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "0 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... Microstruttura \n", + "2 Bolzano, Via Combattenti, 4, Coccinella (azien... Ente gestore \n", + "3 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "4 Bolzano, Via Combattenti, 4, Coccinella (azien... bambini \n", + "5 Bolzano, Via Combattenti, 4, Coccinella (azien... cognome \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome \\\n", + "0 NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "2 Cooperativa Sociale Babycoop \n", + "3 NaN \n", + "4 NaN \n", + "5 nome \n", + "6 NaN \n", + "7 Caio \n", + "\n", + " utente \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 utente aziendale o comunale \n", + "5 NaN \n", + "6 aziendale \n", + "7 comunale \n", + "\n", + " ComuneProvenienza \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + "5 NaN \n", + "6 NaN \n", + "7 Bozen / Bolzano \n", + "\n", + " DataInizio DataFine \n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + "5 NaN NaN \n", + "6 2017-11-20 00:00:00 2020-08-31 00:00:00 \n", + "7 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 353, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 354, + "id": "e1473a30", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 354, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "df = df.drop(labels=range(0, 6), axis=0)\n", + "df.columns\n", + "df2.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 357, + "id": "ead1cd41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 " + ] + }, + "execution_count": 357, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 358, + "id": "05797b5d", + "metadata": {}, + "outputs": [], + "source": [ + "dfout=None" + ] + }, + { + "cell_type": "code", + "execution_count": 359, + "id": "d6eb025d", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.DataFrame(columns=df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 360, + "id": "b7f90c83", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine]\n", + "Index: []" + ] + }, + "execution_count": 360, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 361, + "id": "75a4a5a7", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = df.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 362, + "id": "ea2e2a8b", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.concat([dfout, df2])" + ] + }, + { + "cell_type": "code", + "execution_count": 363, + "id": "9eac701e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 363, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 364, + "id": "0b4d239b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 364, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Cognome\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 374, + "id": "b2af7f5a", + "metadata": {}, + "outputs": [], + "source": [ + "c1 = dfout.groupby(\"Cognome\")[\"DataInizio\"].transform(\"nunique\") == 1\n", + "c2 = dfout.groupby(\"Cognome\")[\"Ente\"].transform(\"count\") > 1" + ] + }, + { + "cell_type": "code", + "execution_count": 375, + "id": "372f47c6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "14 Cooperativa sociale Coccinella \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome Nome utente \\\n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "\n", + " ComuneProvenienza DataInizio DataFine \n", + "14 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 \n", + "7 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 375, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout[c1 & c2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14c412bd", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled7.ipynb b/pages/Jupyter/Untitled7.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..363fcab7ed6e9634e198cf5555ceb88932c9a245 --- /dev/null +++ b/pages/Jupyter/Untitled7.ipynb @@ -0,0 +1,6 @@ +{ + "cells": [], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/Untitled8.ipynb b/pages/Jupyter/Untitled8.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..a093c4d50223e244a76aa56a28be75f39332c22d --- /dev/null +++ b/pages/Jupyter/Untitled8.ipynb @@ -0,0 +1,368 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "586daded", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/home/stfz/notebooks/max/pages/Jupyter'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "457aeff3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/stfz/notebooks/max/pages\n" + ] + } + ], + "source": [ + "cd .." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2bd192f0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Betriebliche_Kitas.py\r\n", + " CalcoloSomme.ipynb\r\n", + "\u001b[0m\u001b[01;34m'Casa Bimbo'\u001b[0m/\r\n", + " covid4_gemeinden.ipynb\r\n", + " dataout.csv\r\n", + " dataout.xlsx\r\n", + "\u001b[01;32m'Erklärung Gemeinden Jahr 2020 Tramin.xlsx'\u001b[0m*\r\n", + " ErroreProportionMAximalStunden.ipynb\r\n", + " \u001b[01;34merrorfiles\u001b[0m/\r\n", + " \u001b[01;34merrorfilesKitas\u001b[0m/\r\n", + "'errori dopo modifica 2021 - Copy.xlsx'\r\n", + "'errori dopo modifica 2021.csv'\r\n", + "'errori dopo modifica 2021.xlsx'\r\n", + " GemeindenComuni.xlsx\r\n", + "'Gemischte KITA.docx'\r\n", + " JahresBericht_Ahrntal_2021_test.xlsx\r\n", + " JahresBericht_Ahrntal_2021.xlsx\r\n", + " Jahresbericht.xlsx\r\n", + " \u001b[01;34mJupyter\u001b[0m/\r\n", + " \u001b[01;34mobsoleti\u001b[0m/\r\n", + " \u001b[01;34moldVersions\u001b[0m/\r\n", + "'prospetto rendicontazione microstrutture miste_Max.xlsx'\r\n", + "'prospetto rendicontazione via combattenti 2019.xlsx'\r\n", + " README.md\r\n", + " riassuntoAutomatico.xlsx\r\n", + " TagesMütterold.py\r\n", + " TagesMütter.py\r\n", + " test2.csv\r\n", + " test.csv\r\n" + ] + } + ], + "source": [ + "ls" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5c2d0e0b", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "226c7f2f", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(\"GemeindenComuni.xlsx\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "2836b911", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneGemeinde
0AldinoAbtei
1AndrianoAhrntal
2AnterivoAldein
3Appiano s.s.d.v.Algund
4AvelengoAltrei
.........
111VelturnoWaidbruck
112VeranoWelsberg-Taisten
113VillabassaWelschnofen
114VillandroWengen
115VipitenoWolkenstein in Gröden
\n", + "

116 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " Comune Gemeinde\n", + "0 Aldino Abtei\n", + "1 Andriano Ahrntal\n", + "2 Anterivo Aldein\n", + "3 Appiano s.s.d.v. Algund\n", + "4 Avelengo Altrei\n", + ".. ... ...\n", + "111 Velturno Waidbruck\n", + "112 Verano Welsberg-Taisten\n", + "113 Villabassa Welschnofen\n", + "114 Villandro Wengen\n", + "115 Vipiteno Wolkenstein in Gröden\n", + "\n", + "[116 rows x 2 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "50079b31", + "metadata": {}, + "outputs": [], + "source": [ + "g = \"Boozen\"" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "52861c17", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pippo\n" + ] + } + ], + "source": [ + "if g not in df[\"Gemeinde\"]:\n", + " print(\"pippo\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "5f78e9d6", + "metadata": {}, + "outputs": [], + "source": [ + "c = df[\"Gemeinde\"] == 'Bozen'" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "f027859e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneGemeinde
8BraiesBozen
\n", + "
" + ], + "text/plain": [ + " Comune Gemeinde\n", + "8 Braies Bozen" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "62edd80d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "print(g in df[\"Gemeinde\"].unique())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "831097c7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/VariabiliDinamiche.ipynb b/pages/Jupyter/VariabiliDinamiche.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..f84dbc19d9dae9b4d94f626ea0180e222543126d --- /dev/null +++ b/pages/Jupyter/VariabiliDinamiche.ipynb @@ -0,0 +1,64 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "464498d1", + "metadata": {}, + "outputs": [], + "source": [ + "x = True" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c6635b84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "bool" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59de54d6", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/coccinella 20219 datum links.xlsx b/pages/Jupyter/coccinella 20219 datum links.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d58426d4ad7310074a2e3dccc70be33eab375dae Binary files /dev/null and b/pages/Jupyter/coccinella 20219 datum links.xlsx differ diff --git a/pages/Jupyter/kitas.ipynb b/pages/Jupyter/kitas.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..819d7e129e078edd2aeaaedb49913385c8b5e9d5 --- /dev/null +++ b/pages/Jupyter/kitas.ipynb @@ -0,0 +1,290 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5bff57df", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"EsempioTimeSeries.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4634608a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.8/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "df1 = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c28713d0", + "metadata": {}, + "outputs": [], + "source": [ + "df = {}\n", + "type(df)\n", + "df[\"sheet0\"] = None\n", + "df[\"sheet1\"] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2f21a70c", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "a391f5de", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7bbd726c", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce').isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce').isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b421fd4a", + "metadata": {}, + "outputs": [], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "36beb1b6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 2017\n", + "7 2017\n", + "8 2018\n", + "9 2018\n", + "10 2019\n", + "Name: DataInizio, dtype: int64" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1[\"DataInizio\"].astype(\"datetime64[ns]\").dt.year" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b0c0b0d7", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d4610b79", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "25246f11", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine, delibera666, delibera543, delibera733, Entrate, errData]\n", + "Index: []" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2980f243", + "metadata": {}, + "outputs": [], + "source": [ + "df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "ff0afa67", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"sheet0\"] = df1\n", + "df[\"sheet1\"] = df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5eedd02b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/kitas_2.ipynb b/pages/Jupyter/kitas_2.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..8410f844a9895df15497ba1d648036ff33f2c1f7 --- /dev/null +++ b/pages/Jupyter/kitas_2.ipynb @@ -0,0 +1,1504 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 405, + "id": "dd1858df", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io" + ] + }, + { + "cell_type": "code", + "execution_count": 406, + "id": "92ce9948", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"prospetto rendicontazione via combattenti 2019.xlsx\"\n", + "fn2 = \"prospetto rendicontazione via combattenti 2019_bis.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 407, + "id": "07cb415e", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn,0)\n", + "df2 = pd.read_excel(fn2,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 408, + "id": "f889b62e", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n", + "df2 = df2.drop([\"Unnamed: 6\", \"Unnamed: 7\"], axis=1)\n", + "df2.columns = [\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"utente\",\n", + " \"ComuneProvenienza\",\n", + " \"DataInizio\",\n", + " \"DataFine\",\n", + " ]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 409, + "id": "9b2fa1f5", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "microstruttura = df.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df.iloc[2]\n", + "ente = ente[1]\n", + "df.insert(0, \"Microstruttura\", microstruttura)\n", + "df.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 410, + "id": "26c83573", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Cooperativa sociale Coccinella'" + ] + }, + "execution_count": 410, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ente" + ] + }, + { + "cell_type": "code", + "execution_count": 411, + "id": "bbf998b5", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "ente = df2.iloc[2]\n", + "ente = ente[2]\n", + "df2.insert(0, \"Ente\", ente)" + ] + }, + { + "cell_type": "code", + "execution_count": 412, + "id": "2ceac119", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
0Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
1Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...MicrostrutturaBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaN
2Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...Ente gestoreCooperativa Sociale BabycoopNaNNaNNaNNaN
3Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...NaNNaNNaNNaNNaNNaN
4Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...bambiniNaNutente aziendale o comunaleSe utente comunale, indicare il Comune di prov...Data inizio assistenza\\nxx.xx.xxxxData fine assistenza\\nxx.xx.xxxx
5Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...cognomenomeNaNNaNNaNNaN
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "0 Cooperativa Sociale Babycoop \n", + "1 Cooperativa Sociale Babycoop \n", + "2 Cooperativa Sociale Babycoop \n", + "3 Cooperativa Sociale Babycoop \n", + "4 Cooperativa Sociale Babycoop \n", + "5 Cooperativa Sociale Babycoop \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "0 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... Microstruttura \n", + "2 Bolzano, Via Combattenti, 4, Coccinella (azien... Ente gestore \n", + "3 Bolzano, Via Combattenti, 4, Coccinella (azien... NaN \n", + "4 Bolzano, Via Combattenti, 4, Coccinella (azien... bambini \n", + "5 Bolzano, Via Combattenti, 4, Coccinella (azien... cognome \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome \\\n", + "0 NaN \n", + "1 Bolzano, Via Combattenti, 4, Coccinella (azien... \n", + "2 Cooperativa Sociale Babycoop \n", + "3 NaN \n", + "4 NaN \n", + "5 nome \n", + "6 NaN \n", + "7 Caio \n", + "\n", + " utente \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 utente aziendale o comunale \n", + "5 NaN \n", + "6 aziendale \n", + "7 comunale \n", + "\n", + " ComuneProvenienza \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 Se utente comunale, indicare il Comune di prov... \n", + "5 NaN \n", + "6 NaN \n", + "7 Bozen / Bolzano \n", + "\n", + " DataInizio DataFine \n", + "0 NaN NaN \n", + "1 NaN NaN \n", + "2 NaN NaN \n", + "3 NaN NaN \n", + "4 Data inizio assistenza\\nxx.xx.xxxx Data fine assistenza\\nxx.xx.xxxx \n", + "5 NaN NaN \n", + "6 2017-11-20 00:00:00 2020-08-31 00:00:00 \n", + "7 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 412, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 413, + "id": "31362375", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 413, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "df = df.drop(labels=range(0, 6), axis=0)\n", + "df.columns\n", + "df2.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 414, + "id": "d1f89688", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 " + ] + }, + "execution_count": 414, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 415, + "id": "e54d5d6c", + "metadata": {}, + "outputs": [], + "source": [ + "dfout=None" + ] + }, + { + "cell_type": "code", + "execution_count": 416, + "id": "c9ef370d", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.DataFrame(columns=df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 417, + "id": "99753418", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Ente, Microstruttura, Cognome, Nome, utente, ComuneProvenienza, DataInizio, DataFine]\n", + "Index: []" + ] + }, + "execution_count": 417, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 418, + "id": "2d1e147a", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = df.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 419, + "id": "67797e3f", + "metadata": {}, + "outputs": [], + "source": [ + "dfout = pd.concat([dfout, df2])" + ] + }, + { + "cell_type": "code", + "execution_count": 420, + "id": "30b5262e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Cooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Cooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Cooperativa sociale Coccinella \n", + "7 Cooperativa sociale Coccinella \n", + "8 Cooperativa sociale Coccinella \n", + "9 Cooperativa sociale Coccinella \n", + "10 Cooperativa sociale Coccinella \n", + "11 Cooperativa sociale Coccinella \n", + "12 Cooperativa sociale Coccinella \n", + "13 Cooperativa sociale Coccinella \n", + "14 Cooperativa sociale Coccinella \n", + "6 Cooperativa Sociale Babycoop \n", + "7 Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 420, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 421, + "id": "97691ba1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 421, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"Cognome\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 442, + "id": "91c7d731", + "metadata": {}, + "outputs": [], + "source": [ + "c1 = dfout.groupby(\"Cognome\")[\"DataInizio\"].transform(\"nunique\") == 1\n", + "c2 = dfout.groupby(\"Cognome\")[\"Ente\"].transform(\"nunique\") > 1" + ] + }, + { + "cell_type": "code", + "execution_count": 443, + "id": "d5d89b41", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome Nome utente \\\n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio Caio comunale \n", + "\n", + " ComuneProvenienza DataInizio DataFine \n", + "14 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 \n", + "7 Bozen / Bolzano 2017-01-15 00:00:00 2020-08-31 00:00:00 " + ] + }, + "execution_count": 443, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout[c1 & c2]" + ] + }, + { + "cell_type": "code", + "execution_count": 433, + "id": "8b0ceda9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Borgo AliceCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Amato MicheleCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Gulino AlexaCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Furlan LeoCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10GUIBERTEAu GaelCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11FRASSANITO AlexCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12SCAFURO GIOVANNI GiovanniCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13NaNCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6NaNCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "6 Borgo Alice Cooperativa sociale Coccinella \n", + "7 Amato Michele Cooperativa sociale Coccinella \n", + "8 Gulino Alexa Cooperativa sociale Coccinella \n", + "9 Furlan Leo Cooperativa sociale Coccinella \n", + "10 GUIBERTEAu Gael Cooperativa sociale Coccinella \n", + "11 FRASSANITO Alex Cooperativa sociale Coccinella \n", + "12 SCAFURO GIOVANNI Giovanni Cooperativa sociale Coccinella \n", + "13 NaN Cooperativa sociale Coccinella \n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "6 NaN Cooperativa Sociale Babycoop \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 433, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": 424, + "id": "c078a8d3", + "metadata": {}, + "outputs": [], + "source": [ + "dfout.insert(0, \"NomeCompleto\", dfout[\"Cognome\"] + \" \" + dfout[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 430, + "id": "a382688b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
NomeCompletoEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Borgo AliceCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...BorgoAlicecomunaleBozen / Bolzano2016-09-05 00:00:002019-08-31 00:00:00
7Amato MicheleCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...AmatoMichelecomunaleBozen / Bolzano2016-10-10 00:00:002019-06-30 00:00:00
8Gulino AlexaCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GulinoAlexacomunaleBozen / Bolzano2016-11-07 00:00:002019-09-02 00:00:00
9Furlan LeoCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FurlanLeocomunaleBozen / Bolzano2017-03-13 00:00:002019-09-01 00:00:00
10GUIBERTEAu GaelCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...GUIBERTEAuGaelaziendaleNaN2017-04-03 00:00:002020-08-31 00:00:00
11FRASSANITO AlexCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...FRASSANITOAlexcomunaleBozen / Bolzano2017-04-18 00:00:002019-08-31 00:00:00
12SCAFURO GIOVANNI GiovanniCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...SCAFURO GIOVANNIGiovannicomunaleBozen / Bolzano2017-08-27 00:00:002019-08-31 00:00:00
13NaNCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-12-20 00:00:002020-08-31 00:00:00
14Tizio CaioCooperativa sociale CoccinellaBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
6NaNCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...PIETROBON FILIPPONaNaziendaleNaN2017-11-20 00:00:002020-08-31 00:00:00
7Tizio CaioCooperativa Sociale BabycoopBolzano, Via Combattenti, 4, Coccinella (azien...TizioCaiocomunaleBozen / Bolzano2017-01-15 00:00:002020-08-31 00:00:00
\n", + "
" + ], + "text/plain": [ + " NomeCompleto Ente \\\n", + "6 Borgo Alice Cooperativa sociale Coccinella \n", + "7 Amato Michele Cooperativa sociale Coccinella \n", + "8 Gulino Alexa Cooperativa sociale Coccinella \n", + "9 Furlan Leo Cooperativa sociale Coccinella \n", + "10 GUIBERTEAu Gael Cooperativa sociale Coccinella \n", + "11 FRASSANITO Alex Cooperativa sociale Coccinella \n", + "12 SCAFURO GIOVANNI Giovanni Cooperativa sociale Coccinella \n", + "13 NaN Cooperativa sociale Coccinella \n", + "14 Tizio Caio Cooperativa sociale Coccinella \n", + "6 NaN Cooperativa Sociale Babycoop \n", + "7 Tizio Caio Cooperativa Sociale Babycoop \n", + "\n", + " Microstruttura Cognome \\\n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... Borgo \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Amato \n", + "8 Bolzano, Via Combattenti, 4, Coccinella (azien... Gulino \n", + "9 Bolzano, Via Combattenti, 4, Coccinella (azien... Furlan \n", + "10 Bolzano, Via Combattenti, 4, Coccinella (azien... GUIBERTEAu \n", + "11 Bolzano, Via Combattenti, 4, Coccinella (azien... FRASSANITO \n", + "12 Bolzano, Via Combattenti, 4, Coccinella (azien... SCAFURO GIOVANNI \n", + "13 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "14 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "6 Bolzano, Via Combattenti, 4, Coccinella (azien... PIETROBON FILIPPO \n", + "7 Bolzano, Via Combattenti, 4, Coccinella (azien... Tizio \n", + "\n", + " Nome utente ComuneProvenienza DataInizio \\\n", + "6 Alice comunale Bozen / Bolzano 2016-09-05 00:00:00 \n", + "7 Michele comunale Bozen / Bolzano 2016-10-10 00:00:00 \n", + "8 Alexa comunale Bozen / Bolzano 2016-11-07 00:00:00 \n", + "9 Leo comunale Bozen / Bolzano 2017-03-13 00:00:00 \n", + "10 Gael aziendale NaN 2017-04-03 00:00:00 \n", + "11 Alex comunale Bozen / Bolzano 2017-04-18 00:00:00 \n", + "12 Giovanni comunale Bozen / Bolzano 2017-08-27 00:00:00 \n", + "13 NaN aziendale NaN 2017-12-20 00:00:00 \n", + "14 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "6 NaN aziendale NaN 2017-11-20 00:00:00 \n", + "7 Caio comunale Bozen / Bolzano 2017-01-15 00:00:00 \n", + "\n", + " DataFine \n", + "6 2019-08-31 00:00:00 \n", + "7 2019-06-30 00:00:00 \n", + "8 2019-09-02 00:00:00 \n", + "9 2019-09-01 00:00:00 \n", + "10 2020-08-31 00:00:00 \n", + "11 2019-08-31 00:00:00 \n", + "12 2019-08-31 00:00:00 \n", + "13 2020-08-31 00:00:00 \n", + "14 2020-08-31 00:00:00 \n", + "6 2020-08-31 00:00:00 \n", + "7 2020-08-31 00:00:00 " + ] + }, + "execution_count": 430, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e921c191", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/Jupyter/miste.xlsx b/pages/Jupyter/miste.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7b9a2b5f4cbcd7c142643b5bb02b1315cd896d86 Binary files /dev/null and b/pages/Jupyter/miste.xlsx differ diff --git a/pages/Jupyter/prospetto rendicontazione via combattenti 2019.xlsx b/pages/Jupyter/prospetto rendicontazione via combattenti 2019.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d836db358ef41fcea548ee4bb7d1c45261cd2ce4 Binary files /dev/null and b/pages/Jupyter/prospetto rendicontazione via combattenti 2019.xlsx differ diff --git a/pages/Jupyter/prospetto rendicontazione via combattenti 2019_bis.xlsx b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_bis.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..59f35f7532bdd5195395e199f8896998d3b0f94c Binary files /dev/null and b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_bis.xlsx differ diff --git a/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noGestore.xlsx b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noGestore.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..390d69d3ac74ebef504c1d589ff0ee638c375f7a Binary files /dev/null and b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noGestore.xlsx differ diff --git a/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noMicro.xlsx b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noMicro.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c34de68052a52d140e84e3edd2492a4eb14cf91b Binary files /dev/null and b/pages/Jupyter/prospetto rendicontazione via combattenti 2019_noMicro.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1f8aaa9b0f863d519a0b924455f21031c50003ab Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..508af8421c186907899380e480cf5b966dc9cec1 Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniax.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniax.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..53df177ef19da166e5a2a6c4631b77964000909f Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniax.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniaxxxxxxx.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniaxxxxxxx.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2d7e45feb9279a364ea659a4aab421bd10f91af4 Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniaxxxxxxx.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniayyyy.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniayyyy.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a3e8aed55fe6ff377c566ce68bb78deb00fdd09f Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2019 Fiera Xeniayyyy.xlsx differ diff --git a/pages/Jupyter/test rendicontazione microstrutture miste 2020 Merano Casa Bimbo.xlsx b/pages/Jupyter/test rendicontazione microstrutture miste 2020 Merano Casa Bimbo.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..df9913d5b0a57eb9b00c1e66a37f81118e83ce8b Binary files /dev/null and b/pages/Jupyter/test rendicontazione microstrutture miste 2020 Merano Casa Bimbo.xlsx differ diff --git a/pages/Jupyter/test_nome.xlsx b/pages/Jupyter/test_nome.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..db2db339dd9f9f7589c3cbb0fffc88b5afc2b186 Binary files /dev/null and b/pages/Jupyter/test_nome.xlsx differ diff --git a/pages/Jupyter/timeseries.ipynb b/pages/Jupyter/timeseries.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..ea03cd554fe5c6f20c2a7e67dfb2b3282e9cee72 --- /dev/null +++ b/pages/Jupyter/timeseries.ipynb @@ -0,0 +1,8530 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 14, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "from collections import Counter\n", + "import ipywidgets as widgets\n", + "import io\n", + "import copy" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5bff57df", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"1-prospetto rendicontazione microstrutture miste 2020.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "4634608a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/stfz/.local/lib/python3.9/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n", + "/home/stfz/.local/lib/python3.9/site-packages/openpyxl/worksheet/_reader.py:312: UserWarning: Data Validation extension is not supported and will be removed\n", + " warn(msg)\n" + ] + } + ], + "source": [ + "\n", + "df1 = pd.read_excel(fn,0,parse_dates=['Unnamed: 4'])\n", + "df2 = pd.read_excel(fn,1)\n", + "\n", + "df1 = df1.drop(['Unnamed: 6', 'Unnamed: 7'], axis=1)\n", + "df1.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]\n", + "df2.columns = [\"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\",\"delibera666\", \"delibera543\",\"delibera733\",\"Entrate\"]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "86a8333d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Cognome object\n", + "Nome object\n", + "utente object\n", + "ComuneProvenienza object\n", + "DataInizio object\n", + "DataFine object\n", + "dtype: object" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "id": "c28713d0", + "metadata": {}, + "outputs": [], + "source": [ + "df = {}\n", + "type(df)\n", + "df[\"sheet0\"] = None\n", + "df[\"sheet1\"] = None" + ] + }, + { + "cell_type": "code", + "execution_count": 237, + "id": "2f21a70c", + "metadata": {}, + "outputs": [], + "source": [ + "microstruttura = df1.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "\n", + "ente = df1.iloc[2]\n", + "ente = ente[1]\n", + "df1.insert(0, \"Microstruttura\", microstruttura)\n", + "df1.insert(0, \"Ente\", ente)\n", + "df1 = df1.drop(labels=range(0, 6), axis=0)\n", + "validi = df1[\"Cognome\"].notna()\n", + "df1 = df1[validi]\n", + "\n", + "microstruttura = df2.iloc[1]\n", + "microstruttura = microstruttura[1]\n", + "ente = df2.iloc[2]\n", + "ente = ente[1]\n", + "df2.insert(0, \"Microstruttura\", microstruttura)\n", + "df2.insert(0, \"Ente\", ente)\n", + "df2 = df2.drop(labels=range(0, 6), axis=0)\n", + "validi = df2[\"Cognome\"].notna()\n", + "df2 = df2[validi]" + ] + }, + { + "cell_type": "code", + "execution_count": 238, + "id": "a34d988a", + "metadata": {}, + "outputs": [], + "source": [ + "#df2" + ] + }, + { + "cell_type": "code", + "execution_count": 239, + "id": "a391f5de", + "metadata": {}, + "outputs": [], + "source": [ + "#df1[\"DataInizio\"] = pd.to_datetime(df1['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df1[\"DataFine\"] = pd.to_datetime(df1['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataInizio\"] = pd.to_datetime(df2['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = pd.to_datetime(df2['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df1[\"DataInizio\"] = df1[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "#df1[\"DataFine\"] = df1[\"DataFine\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 240, + "id": "029df00d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 02.10.2017\n", + "7 02.10.2017\n", + "8 16.08.2018\n", + "9 27.08.2018\n", + "10 10.09.2018\n", + "11 17.09.2018\n", + "12 07.01.2019\n", + "13 07.03.2019\n", + "14 27.05.2019\n", + "15 05.07.2018\n", + "16 11.12.2017\n", + "17 23.08.2018\n", + "18 06.09.2018\n", + "19 26.11.2018\n", + "20 01.10.2018\n", + "21 03.02.2019\n", + "22 01.05.2019\n", + "23 02.04.2019\n", + "24 02.09.2019\n", + "Name: DataInizio, dtype: object" + ] + }, + "execution_count": 240, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1[\"DataInizio\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 241, + "id": "7bbd726c", + "metadata": {}, + "outputs": [], + "source": [ + "condition1 = pd.to_datetime(df2['DataFine'], errors='coerce',infer_datetime_format=True).isnull()\n", + "condition2 = pd.to_datetime(df2['DataInizio'], errors='coerce',infer_datetime_format=True).isnull()\n", + "condition = condition1 | condition2" + ] + }, + { + "cell_type": "code", + "execution_count": 242, + "id": "b421fd4a", + "metadata": {}, + "outputs": [], + "source": [ + "df2['errData'] = np.nan\n", + "df2['errData'] = df2['errData'].astype(\"boolean\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 243, + "id": "36beb1b6", + "metadata": {}, + "outputs": [], + "source": [ + "#df1[\"DataInizio\"].astype(\"datetime64[ns]\").dt.year" + ] + }, + { + "cell_type": "code", + "execution_count": 244, + "id": "b0c0b0d7", + "metadata": {}, + "outputs": [], + "source": [ + "df2.loc[condition, \"errData\"] = True" + ] + }, + { + "cell_type": "code", + "execution_count": 245, + "id": "d4610b79", + "metadata": {}, + "outputs": [], + "source": [ + "c = df2[\"errData\"] == True" + ] + }, + { + "cell_type": "code", + "execution_count": 246, + "id": "25246f11", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.20202173425041009.05True
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020NaN418239714.6True
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.20205644404122058.6True
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021677288982471.05True
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021NaNNaNNaNNaNTrue
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020NaNNaNNaNNaNTrue
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020NaNNaNNaNNaNTrue
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021NaNNaNNaNNaNTrue
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022NaNNaNNaNNaNTrue
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.5241.52067.73True
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.52862067.73True
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023NaNNaNNaNNaNTrue
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021NaNNaNNaNNaNTrue
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine delibera666 \\\n", + "8 comunale Lana 16.08.2018 31.08.2020 217 \n", + "9 comunale Laives 27.08.2018 31.08.2020 NaN \n", + "11 comunale Merano 17.09.2018 31.08.2020 564 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 677 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 NaN \n", + "19 aziendale NaN 26.11.2018 31.08.2020 NaN \n", + "27 aziendale NaN 13.01.2020 31.12.2020 NaN \n", + "28 aziendale NaN 27.01.2020 31.06.2021 NaN \n", + "29 aziendale NaN 10.02.2020 31.06.2022 NaN \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 NaN \n", + "38 aziendale NaN 15.11.2020 31.08.2021 NaN \n", + "\n", + " delibera543 delibera733 Entrate errData \n", + "8 342 504 1009.05 True \n", + "9 418 239 714.6 True \n", + "11 440 412 2058.6 True \n", + "14 288 98 2471.05 True \n", + "17 NaN NaN NaN True \n", + "19 NaN NaN NaN True \n", + "27 NaN NaN NaN True \n", + "28 NaN NaN NaN True \n", + "29 NaN NaN NaN True \n", + "30 330.5 241.5 2067.73 True \n", + "31 330.5 286 2067.73 True \n", + "33 NaN NaN NaN True \n", + "38 NaN NaN NaN True " + ] + }, + "execution_count": 246, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2[c]" + ] + }, + { + "cell_type": "code", + "execution_count": 247, + "id": "0b48041a", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFinedelibera666delibera543delibera733EntrateerrData
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020NaN427.52312341.47<NA>
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020NaN427.52311295.83<NA>
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.20202173425041009.05True
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020NaN418239714.6True
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020535342197481.5<NA>
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.20205644404122058.6True
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021NaN3721973741.25<NA>
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021NaN3901203788.7<NA>
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021677288982471.05True
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020NaNNaNNaNNaN<NA>
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020NaNNaNNaNNaN<NA>
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021NaNNaNNaNNaNTrue
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020NaNNaNNaNNaN<NA>
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020NaNNaNNaNNaNTrue
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021NaNNaNNaNNaN<NA>
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021NaNNaNNaNNaN<NA>
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022NaNNaNNaNNaN<NA>
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020NaNNaNNaNNaN<NA>
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021NaNNaNNaNNaN<NA>
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021NaNNaNNaNNaN<NA>
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022NaNNaNNaNNaN<NA>
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020NaNNaNNaNNaNTrue
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021NaNNaNNaNNaNTrue
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022NaNNaNNaNNaNTrue
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.5241.52067.73True
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022566.5330.52862067.73True
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.202294764703412.87<NA>
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023NaNNaNNaNNaNTrue
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022NaN40NaN1405.25<NA>
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021NaNNaNNaNNaN<NA>
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022NaNNaNNaNNaN<NA>
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021NaN48NaN1119.36<NA>
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021NaNNaNNaNNaNTrue
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine delibera666 \\\n", + "6 comunale Laives 02.10.2017 27.07.2020 NaN \n", + "7 comunale Laives 02.10.2017 27.07.2020 NaN \n", + "8 comunale Lana 16.08.2018 31.08.2020 217 \n", + "9 comunale Laives 27.08.2018 31.08.2020 NaN \n", + "10 comunale Vadena 10.09.2018 31.08.2020 535 \n", + "11 comunale Merano 17.09.2018 31.08.2020 564 \n", + "12 comunale Laives 07.01.2019 31.08.2021 NaN \n", + "13 comunale Laives 07.03.2019 31.08.2021 NaN \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 677 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 NaN \n", + "16 aziendale NaN 11.12.2017 31.08.2020 NaN \n", + "17 aziendale NaN 23.08.2018 31.08.2021 NaN \n", + "18 aziendale NaN 06.09.2018 30.09.2020 NaN \n", + "19 aziendale NaN 26.11.2018 31.08.2020 NaN \n", + "20 aziendale NaN 01.10.2018 31.08.2021 NaN \n", + "21 aziendale NaN 03.02.2019 08.02.2021 NaN \n", + "22 aziendale NaN 01.05.2019 31.08.2022 NaN \n", + "23 aziendale NaN 02.04.2019 31.08.2020 NaN \n", + "24 aziendale NaN 02.09.2019 31.08.2021 NaN \n", + "25 aziendale NaN 03.01.2020 31.08.2021 NaN \n", + "26 aziendale NaN 08.01.2020 31.08.2022 NaN \n", + "27 aziendale NaN 13.01.2020 31.12.2020 NaN \n", + "28 aziendale NaN 27.01.2020 31.06.2021 NaN \n", + "29 aziendale NaN 10.02.2020 31.06.2022 NaN \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 566.5 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 947 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 NaN \n", + "34 comunale Laives 01.09.2020 31.08.2022 NaN \n", + "35 aziendale NaN 07.09.2020 31.08.2021 NaN \n", + "36 aziendale NaN 08.09.2020 31.08.2022 NaN \n", + "37 comunale Laives 05.10.2020 31.12.2021 NaN \n", + "38 aziendale NaN 15.11.2020 31.08.2021 NaN \n", + "\n", + " delibera543 delibera733 Entrate errData \n", + "6 427.5 231 2341.47 \n", + "7 427.5 231 1295.83 \n", + "8 342 504 1009.05 True \n", + "9 418 239 714.6 True \n", + "10 342 197 481.5 \n", + "11 440 412 2058.6 True \n", + "12 372 197 3741.25 \n", + "13 390 120 3788.7 \n", + "14 288 98 2471.05 True \n", + "15 NaN NaN NaN \n", + "16 NaN NaN NaN \n", + "17 NaN NaN NaN True \n", + "18 NaN NaN NaN \n", + "19 NaN NaN NaN True \n", + "20 NaN NaN NaN \n", + "21 NaN NaN NaN \n", + "22 NaN NaN NaN \n", + "23 NaN NaN NaN \n", + "24 NaN NaN NaN \n", + "25 NaN NaN NaN \n", + "26 NaN NaN NaN \n", + "27 NaN NaN NaN True \n", + "28 NaN NaN NaN True \n", + "29 NaN NaN NaN True \n", + "30 330.5 241.5 2067.73 True \n", + "31 330.5 286 2067.73 True \n", + "32 64 70 3412.87 \n", + "33 NaN NaN NaN True \n", + "34 40 NaN 1405.25 \n", + "35 NaN NaN NaN \n", + "36 NaN NaN NaN \n", + "37 48 NaN 1119.36 \n", + "38 NaN NaN NaN True " + ] + }, + "execution_count": 247, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 248, + "id": "2980f243", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"] = df2[\"DataInizio\"].astype(\"datetime64[ns]\")\n", + "#df2[\"DataInizio\"] = pd.to_datetime(df2['DataInizio'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = pd.to_datetime(df2['DataFine'].astype(\"str\"), infer_datetime_format=True)\n", + "#df2[\"DataFine\"] = df2[\"DataFine\"].astype(\"datetime64[ns]\") \n" + ] + }, + { + "cell_type": "code", + "execution_count": 249, + "id": "301e4317", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"].dt.strftime('%d.%m.%Y')" + ] + }, + { + "cell_type": "code", + "execution_count": 250, + "id": "d47d8671", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"] = df2[\"DataInizio\"].dt.strftime('%m.%d.%Y')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 251, + "id": "3882c1e6", + "metadata": {}, + "outputs": [], + "source": [ + "#df2[\"DataInizio\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 252, + "id": "59461438", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"sheet0\"] = df1\n", + "df[\"sheet1\"] = df2" + ] + }, + { + "cell_type": "code", + "execution_count": 253, + "id": "4052946e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 " + ] + }, + "execution_count": 253, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"sheet0\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 254, + "id": "32908ff9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 254, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"sheet1\"][[\"Ente\", \"Microstruttura\", \"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": 255, + "id": "b4daef8a", + "metadata": {}, + "outputs": [], + "source": [ + "frames = [df[\"sheet0\"], df[\"sheet1\"][[\"Ente\", \"Microstruttura\", \"Cognome\", \"Nome\", \"utente\", \"ComuneProvenienza\", \"DataInizio\",\"DataFine\"]]]\n", + "\n", + "result = pd.concat(frames)" + ] + }, + { + "cell_type": "code", + "execution_count": 256, + "id": "90bcfdcf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "22 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 256, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result.sort_values(by=['DataInizio'])" + ] + }, + { + "cell_type": "code", + "execution_count": 257, + "id": "46dfa0b4", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = result" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "id": "5748e823", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
EnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
6Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
7Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
8Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
9Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
10Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
11Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
12Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
13Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
14Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
15Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
16Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
18Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
19Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
20Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
21Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
22Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
23Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
24Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
25Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
26Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
27Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
29Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
30Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
31Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
32Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
33Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
34Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
35Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
36Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
37Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
38Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " Ente \\\n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "6 Xenia Cooperativa Sociale Onlus \n", + "7 Xenia Cooperativa Sociale Onlus \n", + "8 Xenia Cooperativa Sociale Onlus \n", + "9 Xenia Cooperativa Sociale Onlus \n", + "10 Xenia Cooperativa Sociale Onlus \n", + "11 Xenia Cooperativa Sociale Onlus \n", + "12 Xenia Cooperativa Sociale Onlus \n", + "13 Xenia Cooperativa Sociale Onlus \n", + "14 Xenia Cooperativa Sociale Onlus \n", + "15 Xenia Cooperativa Sociale Onlus \n", + "16 Xenia Cooperativa Sociale Onlus \n", + "17 Xenia Cooperativa Sociale Onlus \n", + "18 Xenia Cooperativa Sociale Onlus \n", + "19 Xenia Cooperativa Sociale Onlus \n", + "20 Xenia Cooperativa Sociale Onlus \n", + "21 Xenia Cooperativa Sociale Onlus \n", + "22 Xenia Cooperativa Sociale Onlus \n", + "23 Xenia Cooperativa Sociale Onlus \n", + "24 Xenia Cooperativa Sociale Onlus \n", + "25 Xenia Cooperativa Sociale Onlus \n", + "26 Xenia Cooperativa Sociale Onlus \n", + "27 Xenia Cooperativa Sociale Onlus \n", + "28 Xenia Cooperativa Sociale Onlus \n", + "29 Xenia Cooperativa Sociale Onlus \n", + "30 Xenia Cooperativa Sociale Onlus \n", + "31 Xenia Cooperativa Sociale Onlus \n", + "32 Xenia Cooperativa Sociale Onlus \n", + "33 Xenia Cooperativa Sociale Onlus \n", + "34 Xenia Cooperativa Sociale Onlus \n", + "35 Xenia Cooperativa Sociale Onlus \n", + "36 Xenia Cooperativa Sociale Onlus \n", + "37 Xenia Cooperativa Sociale Onlus \n", + "38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Nalles 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "6 comunale Laives 02.10.2017 27.07.2020 \n", + "7 comunale Laives 02.10.2017 27.07.2020 \n", + "8 comunale Lana 16.08.2018 31.08.2020 \n", + "9 comunale Laives 27.08.2018 31.08.2020 \n", + "10 comunale Vadena 10.09.2018 31.08.2020 \n", + "11 comunale Merano 17.09.2018 31.08.2020 \n", + "12 comunale Laives 07.01.2019 31.08.2021 \n", + "13 comunale Laives 07.03.2019 31.08.2021 \n", + "14 comunale Tesimo 27.05.2019 31.08.2021 \n", + "15 aziendale NaN 05.07.2018 31.08.2020 \n", + "16 aziendale NaN 11.12.2017 31.08.2020 \n", + "17 aziendale NaN 23.08.2018 31.08.2021 \n", + "18 aziendale NaN 06.09.2018 30.09.2020 \n", + "19 aziendale NaN 26.11.2018 31.08.2020 \n", + "20 aziendale NaN 01.10.2018 31.08.2021 \n", + "21 aziendale NaN 03.02.2019 08.02.2021 \n", + "22 aziendale NaN 01.05.2019 31.08.2022 \n", + "23 aziendale NaN 02.04.2019 31.08.2020 \n", + "24 aziendale NaN 02.09.2019 31.08.2021 \n", + "25 aziendale NaN 03.01.2020 31.08.2021 \n", + "26 aziendale NaN 08.01.2020 31.08.2022 \n", + "27 aziendale NaN 13.01.2020 31.12.2020 \n", + "28 aziendale NaN 27.01.2020 31.06.2021 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "31 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "32 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "33 aziendale NaN 20.08.2020 31.08.2023 \n", + "34 comunale Laives 01.09.2020 31.08.2022 \n", + "35 aziendale NaN 07.09.2020 31.08.2021 \n", + "36 aziendale NaN 08.09.2020 31.08.2022 \n", + "37 comunale Laives 05.10.2020 31.12.2021 \n", + "38 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 200, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 258, + "id": "8bc9dc9b", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 " + ] + }, + "execution_count": 258, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx = dfx.reset_index()\n", + "result = result.reset_index()\n", + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 228, + "id": "222e633d", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PILATO MARTIN\n", + "PILATO NOCOL\n", + "OIENI GIADA\n", + "SCAFAR VIKTORIA\n", + "TURANI NINA\n", + "MAXIMILIAN COCCO PAOLO\n", + "FERRARESE LEONARDO\n", + "BURAGLIO NICOL\n", + "MAYR DUFFEK VINCENT\n", + "TARGA MATILDE\n", + "COLLATUZZO TOMMASO\n", + "ISSAMM LAMRI\n", + "INNEREBNER MIA\n", + "BATTAN BRYAN LORENZO\n", + "NOMAN SOFIA\n", + "ER RQXQ RAZAN\n", + "BEQIRAJ KLARA\n", + "BEZZI GABRIEL\n", + "SCHMITTNER RAPHAEL\n", + "PILATO MARTIN\n", + "PILATO NICOL\n", + "OIENI GIADA\n", + "SCAFAR VIKTORIA\n", + "TURANI NINA\n", + "MAXIMILIAN COCCO PAOLO\n", + "FERRARESE LEONARDO\n", + "BURAGLIO NICOL\n", + "MAYR DUFFEK VINCENT\n", + "TARGA MATILDE\n", + "COLLATUZZO TOMMASO\n", + "ISSAMM LAMRI\n", + "INNEREBNER MIA\n", + "BATTAN BRYAN LORENZO\n", + "NOMAN SOFIA\n", + "ER RQXQ RAZAN\n", + "BEQIRAJ KLARA\n", + "BEZZI GABRIEL\n", + "SCHMITTNER RAPHAEL\n", + "TUTZER SOPHIE\n", + "VRENJO LOLA\n", + "BEQIRAJ EDUART\n", + "VRENJO DEA\n", + "CASTIONI MICHELE\n", + "PISCULA DAVID\n", + "PISCULA MICHAEL\n", + "OBKIRCHER REBECCA\n", + "SCHULLIAN FELIZIA\n", + "DI PASQUALE ESTHER\n", + "RISO ALICE\n", + "CHIFU SERENA\n", + "TOKA BREDLEY\n", + "TUTZER SOPHIE\n" + ] + } + ], + "source": [ + "for ind in dfx.index:\n", + " print(dfx['Cognome'][ind], dfx['Nome'][ind])" + ] + }, + { + "cell_type": "code", + "execution_count": 259, + "id": "fcf6e153", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = dfx.sort_values(by=['DataInizio'])\n", + "result = result.sort_values(by=['DataInizio'])" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "id": "3c35780e", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 230, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 262, + "id": "b9a3bee9", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['index', 'Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 262, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 265, + "id": "90794b99", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
3522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
4734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
3320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
1723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
1824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
17Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
3825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
1521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
4532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
2815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
5037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
3118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
2512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
2613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
4835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
3926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
4936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
4229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
2310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
2916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
4027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
5138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
28Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
4330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
4431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
2411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
4633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
3219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
4128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
2714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "35 22 Xenia Cooperativa Sociale Onlus \n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "47 34 Xenia Cooperativa Sociale Onlus \n", + "33 20 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "17 23 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "18 24 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "19 6 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "1 7 Xenia Cooperativa Sociale Onlus \n", + "20 7 Xenia Cooperativa Sociale Onlus \n", + "38 25 Xenia Cooperativa Sociale Onlus \n", + "15 21 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "45 32 Xenia Cooperativa Sociale Onlus \n", + "28 15 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "50 37 Xenia Cooperativa Sociale Onlus \n", + "31 18 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "25 12 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "26 13 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "48 35 Xenia Cooperativa Sociale Onlus \n", + "39 26 Xenia Cooperativa Sociale Onlus \n", + "49 36 Xenia Cooperativa Sociale Onlus \n", + "42 29 Xenia Cooperativa Sociale Onlus \n", + "23 10 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "29 16 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "40 27 Xenia Cooperativa Sociale Onlus \n", + "51 38 Xenia Cooperativa Sociale Onlus \n", + "2 8 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "43 30 Xenia Cooperativa Sociale Onlus \n", + "44 31 Xenia Cooperativa Sociale Onlus \n", + "24 11 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "46 33 Xenia Cooperativa Sociale Onlus \n", + "11 17 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "32 19 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "41 28 Xenia Cooperativa Sociale Onlus \n", + "27 14 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "22 9 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "35 aziendale NaN 01.05.2019 31.08.2022 \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "47 comunale Laives 01.09.2020 31.08.2022 \n", + "33 aziendale NaN 01.10.2018 31.08.2021 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "17 aziendale NaN 02.04.2019 31.08.2020 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "18 aziendale NaN 02.09.2019 31.08.2021 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "19 comunale Laives 02.10.2017 27.07.2020 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "1 comunale Laives 02.10.2017 27.07.2020 \n", + "20 comunale Laives 02.10.2017 27.07.2020 \n", + "38 aziendale NaN 03.01.2020 31.08.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "45 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "28 aziendale NaN 05.07.2018 31.08.2020 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "50 comunale Laives 05.10.2020 31.12.2021 \n", + "31 aziendale NaN 06.09.2018 30.09.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "25 comunale Laives 07.01.2019 31.08.2021 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "26 comunale Laives 07.03.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "48 aziendale NaN 07.09.2020 31.08.2021 \n", + "39 aziendale NaN 08.01.2020 31.08.2022 \n", + "49 aziendale NaN 08.09.2020 31.08.2022 \n", + "42 aziendale NaN 10.02.2020 31.06.2022 \n", + "23 comunale Vadena 10.09.2018 31.08.2020 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "29 aziendale NaN 11.12.2017 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "40 aziendale NaN 13.01.2020 31.12.2020 \n", + "51 aziendale NaN 15.11.2020 31.08.2021 \n", + "2 comunale Lana 16.08.2018 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "43 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "44 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "24 comunale Merano 17.09.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "46 aziendale NaN 20.08.2020 31.08.2023 \n", + "11 aziendale NaN 23.08.2018 31.08.2021 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "32 aziendale NaN 26.11.2018 31.08.2020 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "41 aziendale NaN 27.01.2020 31.06.2021 \n", + "27 comunale Tesimo 27.05.2019 31.08.2021 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "22 comunale Laives 27.08.2018 31.08.2020 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 265, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 276, + "id": "60337a79", + "metadata": {}, + "outputs": [], + "source": [ + "finddups = dfx[[\"Cognome\", \"Nome\", \"utente\", \"DataInizio\", \"DataFine\"]].duplicated()" + ] + }, + { + "cell_type": "code", + "execution_count": 279, + "id": "a9e24990", + "metadata": {}, + "outputs": [], + "source": [ + "dfx = dfx[finddups]" + ] + }, + { + "cell_type": "code", + "execution_count": 280, + "id": "6afc40ca", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
06Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
39Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "0 6 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "6 12 Xenia Cooperativa Sociale Onlus \n", + "7 13 Xenia Cooperativa Sociale Onlus \n", + "4 10 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "21 8 Xenia Cooperativa Sociale Onlus \n", + "5 11 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "8 14 Xenia Cooperativa Sociale Onlus \n", + "3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "0 comunale Laives 02.10.2017 27.07.2020 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "6 comunale Laives 07.01.2019 31.08.2021 \n", + "7 comunale Laives 07.03.2019 31.08.2021 \n", + "4 comunale Vadena 10.09.2018 31.08.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "21 comunale Lana 16.08.2018 31.08.2020 \n", + "5 comunale Nalles 17.09.2018 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 \n", + "8 comunale Tesimo 27.05.2019 31.08.2021 \n", + "3 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 280, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 272, + "id": "8e3006ec", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> contatore comunale = 0 e contatore aziendale = 1\n", + "\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> contatore comunale = 0 e contatore aziendale = 2\n", + "\n", + "bimbo comunale\t--> DI PASQUALE ESTHER \t--> contatore comunale = 1 e contatore aziendale = 2\n", + "\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> contatore comunale = 1 e contatore aziendale = 3\n", + "\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> contatore comunale = 1 e contatore aziendale = 4\n", + "\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> contatore comunale = 1 e contatore aziendale = 5\n", + "\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> contatore comunale = 1 e contatore aziendale = 6\n", + "\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> contatore comunale = 1 e contatore aziendale = 7\n", + "\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> contatore comunale = 1 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO MARTIN \t--> contatore comunale = 2 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO MARTIN \t--> contatore comunale = 3 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO NOCOL \t--> contatore comunale = 4 e contatore aziendale = 8\n", + "\n", + "bimbo comunale\t--> PILATO NICOL \t--> contatore comunale = 5 e contatore aziendale = 8\n", + "\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> contatore comunale = 5 e contatore aziendale = 9\n", + "\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> contatore comunale = 5 e contatore aziendale = 10\n", + "\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> contatore comunale = 5 e contatore aziendale = 11\n", + "\n", + "bimbo comunale\t--> OBKIRCHER REBECCA \t--> contatore comunale = 6 e contatore aziendale = 11\n", + "\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> contatore comunale = 6 e contatore aziendale = 12\n", + "\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> contatore comunale = 6 e contatore aziendale = 13\n", + "\n", + "bimbo comunale\t--> TOKA BREDLEY \t--> contatore comunale = 7 e contatore aziendale = 13\n", + "\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> contatore comunale = 7 e contatore aziendale = 14\n", + "\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> contatore comunale = 7 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> contatore comunale = 8 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> contatore comunale = 9 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> contatore comunale = 10 e contatore aziendale = 15\n", + "\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> contatore comunale = 11 e contatore aziendale = 15\n", + "\n", + "bimbo aziendale\t--> RISO ALICE \t--> contatore comunale = 11 e contatore aziendale = 16\n", + "\n", + "bimbo aziendale\t--> VRENJO LOLA \t--> contatore comunale = 11 e contatore aziendale = 17\n", + "\n", + "CHIFU SERENA contatore aziendale = 18\n", + "Sottrazione --> contatore aziendale = 17\n", + "CHIFU SERENA contatore aziendale = 17\n", + "Sottrazione --> contatore aziendale = 16\n", + "bimbo aziendale\t--> CHIFU SERENA \t--> contatore comunale = 11 e contatore aziendale = 16\n", + "\n", + "bimbo aziendale\t--> CASTIONI MICHELE \t--> contatore comunale = 11 e contatore aziendale = 17\n", + "\n", + "bimbo comunale\t--> TURANI NINA \t--> contatore comunale = 12 e contatore aziendale = 17\n", + "\n", + "bimbo comunale\t--> TURANI NINA \t--> contatore comunale = 13 e contatore aziendale = 17\n", + "\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> contatore comunale = 13 e contatore aziendale = 18\n", + "\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> contatore comunale = 13 e contatore aziendale = 19\n", + "\n", + "bimbo aziendale\t--> BEQIRAJ EDUART \t--> contatore comunale = 13 e contatore aziendale = 20\n", + "\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> contatore comunale = 13 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> OIENI GIADA \t--> contatore comunale = 14 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> OIENI GIADA \t--> contatore comunale = 15 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> PISCULA DAVID \t--> contatore comunale = 16 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> PISCULA MICHAEL \t--> contatore comunale = 17 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> contatore comunale = 18 e contatore aziendale = 21\n", + "\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> contatore comunale = 19 e contatore aziendale = 21\n", + "\n", + "bimbo aziendale\t--> SCHULLIAN FELIZIA \t--> contatore comunale = 19 e contatore aziendale = 22\n", + "\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> contatore comunale = 19 e contatore aziendale = 23\n", + "\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> contatore comunale = 19 e contatore aziendale = 24\n", + "\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> contatore comunale = 19 e contatore aziendale = 25\n", + "\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> contatore comunale = 19 e contatore aziendale = 26\n", + "\n", + "bimbo aziendale\t--> VRENJO DEA \t--> contatore comunale = 19 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> contatore comunale = 20 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> contatore comunale = 21 e contatore aziendale = 27\n", + "\n", + "SCAFAR VIKTORIA contatore comunale = 22\n", + "Sottrazione --> contatore comunale = 21\n", + "SCAFAR VIKTORIA contatore comunale = 21\n", + "Sottrazione --> contatore comunale = 20\n", + "SCAFAR VIKTORIA contatore comunale = 20\n", + "Sottrazione --> contatore comunale = 19\n", + "SCAFAR VIKTORIA contatore comunale = 19\n", + "Sottrazione --> contatore comunale = 18\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> contatore comunale = 18 e contatore aziendale = 27\n", + "\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> contatore comunale = 19 e contatore aziendale = 27\n", + "\n", + "################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\n" + ] + } + ], + "source": [ + "DEBUGMODE = True\n", + "#result = dfx\n", + "cont_c = 0\n", + "cont_a = 0\n", + "datafineprecedenti_c = []\n", + "datafineprecedenti_a = []\n", + "\n", + "print(\n", + " \"################### INIZIO ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\"\n", + ")\n", + "\n", + "# dobbiamo per forza iterare sui record, utilizziamo il metodo dell'indice\n", + "for ind in result.index:\n", + " # si tratta di utente comunale?\n", + " if result[\"utente\"][ind] == \"comunale\":\n", + " cont_c += 1 # incrementiamo il contatore\n", + " datafineprecedenti_c.append(\n", + " str(result[\"DataFine\"][ind])\n", + " ) # salviamo la data fine incontrata dureante iterazione\n", + " d_c = copy.copy(\n", + " datafineprecedenti_c\n", + " ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop\n", + " for (\n", + " a\n", + " ) in (\n", + " datafineprecedenti_c\n", + " ): # loopiamo tutte le data fine incontrate precedentemente\n", + " if (\n", + " str(result[\"DataInizio\"][ind]) > a\n", + " ): # se incontrata una data inizio superiore a una data fine già incontrata\n", + " if DEBUGMODE:\n", + " print(\n", + " result[\"Cognome\"][ind]\n", + " + \" \"\n", + " + result[\"Nome\"][ind]\n", + " + \" contatore comunale = \"\n", + " + str(cont_c)\n", + " )\n", + " cont_c -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\"Sottrazione --> contatore comunale = \" + str(cont_c))\n", + " d_c.remove(\n", + " a\n", + " ) # togliamo la data \"consumata\" dalla lista (copiata)\n", + " datafineprecedenti_c = copy.copy(\n", + " d_c\n", + " ) # deep copy della lista aggiornata (senza data fine \"consumate\")\n", + "\n", + " # si tratta di utente aziendale?\n", + " elif result[\"utente\"][ind] == \"aziendale\":\n", + " cont_a += 1 # incrementiamo il contatore\n", + " datafineprecedenti_a.append(\n", + " str(result[\"DataFine\"][ind])\n", + " ) # salviamo la data fine incontrata dureante iterazione\n", + " d_a = copy.copy(\n", + " datafineprecedenti_a\n", + " ) # facciamo deep copy della lista, perch'in seguito cancelliamo dalla copia per non avere problemi nel loop\n", + " for (\n", + " a\n", + " ) in (\n", + " datafineprecedenti_a\n", + " ): # loopiamo tutte le data fine incontrate precedentemente\n", + " if (\n", + " str(result[\"DataInizio\"][ind]) > a\n", + " ): # se incontrata una data inizio superiore a una data fine già incontrata\n", + " if DEBUGMODE:\n", + " print(\n", + " result[\"Cognome\"][ind]\n", + " + \" \"\n", + " + result[\"Nome\"][ind]\n", + " + \" contatore aziendale = \"\n", + " + str(cont_a)\n", + " )\n", + " cont_a -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\"Sottrazione --> contatore aziendale = \" + str(cont_a))\n", + " d_a.remove(\n", + " a\n", + " ) # togliamo la data \"consumata\" dalla lista (copiata)\n", + " datafineprecedenti_a = copy.copy(\n", + " d_a\n", + " ) # deep copy della lista aggiornata (senza data fine \"consumate\")\n", + "\n", + " if DEBUGMODE:\n", + " print(\"bimbo \" + result[\"utente\"][ind] + \"\\t--> \" + result[\"Cognome\"][ind] + \" \" + result[\"Nome\"][ind] + \" \\t--> contatore comunale = \" + str(cont_c) + \" e contatore aziendale = \" + str(cont_a))\n", + " # vediamo se la condizione che potrebbe triggare la rimozione di un bimbo è soddisfatta\n", + " if (\n", + " (cont_c >= cont_a)\n", + " and result[\"utente\"][ind] == \"comunale\"\n", + " and result[\"DataInizio\"][ind]\n", + " >= pd.to_datetime(\"03.10.2017\", format=\"%d.%m.%Y\")\n", + " ):\n", + "\n", + " # st.write(\"trovato!!!!!!!\")\n", + " print(\n", + " f\"[*] Bimbo {result['Cognome'][ind].upper()} {result['Nome'][ind].upper()} in eccesso comunale, in data {result['DataInizio'].dt.strftime('%d.%m.%Y')[ind]} con ore 666 --> {result['delibera666'][ind]}\"\n", + " )\n", + " cont_c -= 1 # sottraiamo contatore\n", + " if DEBUGMODE:\n", + " print(\n", + " \"tolto bimbo: contatore comunale = \"\n", + " + str(cont_c)\n", + " + \" e contatore aziendale = \"\n", + " + str(cont_a)\n", + " )\n", + " print()\n", + "print(\n", + " \"################### FINE ELENCO_BAMBINI CANDIDATI RIMOZIONE ###################\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 231, + "id": "3b18d4b0", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> cont_c = 0 and cont_a = 1\n", + "bimbo aziendale\t--> BEQIRAJ KLARA \t--> cont_c = 0 and cont_a = 2\n", + "bimbo comunale\t--> DI PASQUALE ESTHER \t--> cont_c = 1 and cont_a = 2\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> cont_c = 1 and cont_a = 3\n", + "bimbo aziendale\t--> NOMAN SOFIA \t--> cont_c = 1 and cont_a = 4\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> cont_c = 1 and cont_a = 5\n", + "bimbo aziendale\t--> BEZZI GABRIEL \t--> cont_c = 1 and cont_a = 6\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> cont_c = 1 and cont_a = 7\n", + "bimbo aziendale\t--> SCHMITTNER RAPHAEL \t--> cont_c = 1 and cont_a = 8\n", + "bimbo comunale\t--> PILATO MARTIN \t--> cont_c = 2 and cont_a = 8\n", + "bimbo comunale\t--> PILATO MARTIN \t--> cont_c = 3 and cont_a = 8\n", + "bimbo comunale\t--> PILATO NOCOL \t--> cont_c = 4 and cont_a = 8\n", + "bimbo comunale\t--> PILATO NICOL \t--> cont_c = 5 and cont_a = 8\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> cont_c = 5 and cont_a = 9\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> cont_c = 5 and cont_a = 10\n", + "bimbo aziendale\t--> ER RQXQ RAZAN \t--> cont_c = 5 and cont_a = 11\n", + "bimbo comunale\t--> OBKIRCHER REBECCA \t--> cont_c = 6 and cont_a = 11\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> cont_c = 6 and cont_a = 12\n", + "bimbo aziendale\t--> TARGA MATILDE \t--> cont_c = 6 and cont_a = 13\n", + "bimbo comunale\t--> TOKA BREDLEY \t--> cont_c = 7 and cont_a = 13\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> cont_c = 7 and cont_a = 14\n", + "bimbo aziendale\t--> INNEREBNER MIA \t--> cont_c = 7 and cont_a = 15\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> cont_c = 8 and cont_a = 15\n", + "bimbo comunale\t--> FERRARESE LEONARDO \t--> cont_c = 9 and cont_a = 15\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> cont_c = 10 and cont_a = 15\n", + "bimbo comunale\t--> BURAGLIO NICOL \t--> cont_c = 11 and cont_a = 15\n", + "bimbo aziendale\t--> RISO ALICE \t--> cont_c = 11 and cont_a = 16\n", + "bimbo aziendale\t--> VRENJO LOLA \t--> cont_c = 11 and cont_a = 17\n", + "\n", + "CHIFU SERENA cont_a = 18\n", + "Sottrazione --> cont_a = 17\n", + "\n", + "\n", + "CHIFU SERENA cont_a = 17\n", + "Sottrazione --> cont_a = 16\n", + "\n", + "bimbo aziendale\t--> CHIFU SERENA \t--> cont_c = 11 and cont_a = 16\n", + "bimbo aziendale\t--> CASTIONI MICHELE \t--> cont_c = 11 and cont_a = 17\n", + "bimbo comunale\t--> TURANI NINA \t--> cont_c = 12 and cont_a = 17\n", + "bimbo comunale\t--> TURANI NINA \t--> cont_c = 13 and cont_a = 17\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> cont_c = 13 and cont_a = 18\n", + "bimbo aziendale\t--> COLLATUZZO TOMMASO \t--> cont_c = 13 and cont_a = 19\n", + "bimbo aziendale\t--> BEQIRAJ EDUART \t--> cont_c = 13 and cont_a = 20\n", + "bimbo aziendale\t--> TUTZER SOPHIE \t--> cont_c = 13 and cont_a = 21\n", + "bimbo comunale\t--> OIENI GIADA \t--> cont_c = 14 and cont_a = 21\n", + "bimbo comunale\t--> OIENI GIADA \t--> cont_c = 15 and cont_a = 21\n", + "bimbo comunale\t--> PISCULA DAVID \t--> cont_c = 16 and cont_a = 21\n", + "bimbo comunale\t--> PISCULA MICHAEL \t--> cont_c = 17 and cont_a = 21\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> cont_c = 18 and cont_a = 21\n", + "bimbo comunale\t--> MAXIMILIAN COCCO PAOLO \t--> cont_c = 19 and cont_a = 21\n", + "bimbo aziendale\t--> SCHULLIAN FELIZIA \t--> cont_c = 19 and cont_a = 22\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> cont_c = 19 and cont_a = 23\n", + "bimbo aziendale\t--> ISSAMM LAMRI \t--> cont_c = 19 and cont_a = 24\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> cont_c = 19 and cont_a = 25\n", + "bimbo aziendale\t--> BATTAN BRYAN LORENZO \t--> cont_c = 19 and cont_a = 26\n", + "bimbo aziendale\t--> VRENJO DEA \t--> cont_c = 19 and cont_a = 27\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> cont_c = 20 and cont_a = 27\n", + "bimbo comunale\t--> MAYR DUFFEK VINCENT \t--> cont_c = 21 and cont_a = 27\n", + "\n", + "SCAFAR VIKTORIA cont_c = 22\n", + "Sottrazione --> cont_c = 21\n", + "\n", + "SCAFAR VIKTORIA cont_c = 21\n", + "Sottrazione --> cont_c = 20\n", + "\n", + "SCAFAR VIKTORIA cont_c = 20\n", + "Sottrazione --> cont_c = 19\n", + "\n", + "SCAFAR VIKTORIA cont_c = 19\n", + "Sottrazione --> cont_c = 18\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> cont_c = 18 and cont_a = 27\n", + "bimbo comunale\t--> SCAFAR VIKTORIA \t--> cont_c = 19 and cont_a = 27\n", + "\n", + "################### END OF ITERATION ###################\n" + ] + } + ], + "source": [ + "cont_c = 0\n", + "cont_a = 0\n", + "datafineprecedenti_c = []\n", + "datafineprecedenti_a = []\n", + "\n", + "for ind in dfx.index:\n", + " \n", + " if dfx['utente'][ind] == \"comunale\":\n", + " cont_c += 1\n", + " datafineprecedenti_c.append(str(dfx[\"DataFine\"][ind]))\n", + " d_c = copy.copy(datafineprecedenti_c)\n", + " for a in datafineprecedenti_c:\n", + " if str(dfx[\"DataInizio\"][ind]) > a:\n", + " print()\n", + " print(dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] +\" cont_c = \" + str(cont_c))\n", + " cont_c -= 1\n", + " print(\"Sottrazione --> cont_c = \" + str(cont_c))\n", + " d_c.remove(a)\n", + " datafineprecedenti_c = copy.copy(d_c)\n", + " \n", + " \n", + " elif dfx['utente'][ind] == \"aziendale\":\n", + " cont_a += 1\n", + " datafineprecedenti_a.append(str(dfx[\"DataFine\"][ind]))\n", + " d_a = copy.copy(datafineprecedenti_a)\n", + " for a in datafineprecedenti_a:\n", + " if str(dfx[\"DataInizio\"][ind]) > a:\n", + " print()\n", + " print(dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] +\" cont_a = \" + str(cont_a))\n", + " cont_a -= 1\n", + " print(\"Sottrazione --> cont_a = \" + str(cont_a))\n", + " d_a.remove(a)\n", + " print()\n", + " datafineprecedenti_a = copy.copy(d_a)\n", + " \n", + " \n", + " print(\"bimbo \" + dfx[\"utente\"][ind] + \"\\t--> \" + dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] + \" \\t--> cont_c = \" + str(cont_c) + \" and cont_a = \" + str(cont_a)) \n", + " \n", + " if (cont_c >= cont_a) and dfx[\"utente\"][ind] == \"comunale\" and dfx['DataInizio'][ind] >= pd.to_datetime(\"3.10.2017\", format=\"%d.%m.%Y\"):\n", + " print()\n", + " print(\"Bimbo \" + dfx[\"Cognome\"][ind] + \" \" + dfx[\"Nome\"][ind] + \" \\tin eccesso COMUNALE, in data \" + str(dfx[\"DataInizio\"].dt.strftime('%d/%m/%Y')[ind]))\n", + " cont_c -= 1\n", + " print(\"tolto bimbo: cont_c = \" + str(cont_c) + \" and cont_a = \" + str(cont_a)) \n", + " print()\n", + "print() \n", + "print(\"################### END OF ITERATION ###################\")\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 209, + "id": "4486acde", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
level_0indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
03522Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
11622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
24734Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)DI PASQUALEESTHERcomunaleLaives01.09.202031.08.2022
33320Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
41420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
51723Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
63623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
71824Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
83724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
12207Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONICOLcomunaleLaives02.10.201727.07.2020
1117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATONOCOLcomunaleLaives02.10.201727.07.2020
9196Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
1006Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PILATOMARTINcomunaleLaives02.10.201727.07.2020
133825Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN03.01.202031.08.2021
141521Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
153421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
164532Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OBKIRCHERREBECCAcomunaleCornedo all'Isarco03.06.202031.08.2022
172815Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
18915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
195037Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TOKABREDLEYcomunaleLaives05.10.202031.12.2021
203118Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
211218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
222512Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
23612Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)FERRARESELEONARDOcomunaleLaives07.01.201931.08.2021
25713Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
242613Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BURAGLIONICOLcomunaleLaives07.03.201931.08.2021
264835Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)RISOALICEaziendaleNaN07.09.202031.08.2021
273926Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJOLOLAaziendaleNaN08.01.202031.08.2022
284936Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CHIFUSERENAaziendaleNaN08.09.202031.08.2022
294229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)CASTIONIMICHELEaziendaleNaN10.02.202031.06.2022
302310Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
31410Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TURANININAcomunaleVadena10.09.201831.08.2020
322916Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
331016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
344027Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJEDUARTaziendaleNaN13.01.202031.12.2020
355138Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TUTZERSOPHIEaziendaleNaN15.11.202031.08.2021
37218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
3628Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)OIENIGIADAcomunaleLana16.08.201831.08.2020
394431Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULAMICHAELcomunaleCornedo all'Isarco17.02.202031.08.2022
384330Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)PISCULADAVIDcomunaleCornedo all'Isarco17.02.202031.08.2022
402411Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleMerano17.09.201831.08.2020
41511Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAXIMILIAN COCCOPAOLOcomunaleNalles17.09.201831.08.2020
424633Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHULLIANFELIZIAaziendaleNaN20.08.202031.08.2023
431117Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
443017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
453219Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
461319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
474128Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)VRENJODEAaziendaleNaN27.01.202031.06.2021
482714Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
49814Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)MAYR DUFFEKVINCENTcomunaleTesimo27.05.201931.08.2021
50229Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
5139Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCAFARVIKTORIAcomunaleLaives27.08.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " level_0 index Ente \\\n", + "0 35 22 Xenia Cooperativa Sociale Onlus \n", + "1 16 22 Xenia Cooperativa Sociale Onlus \n", + "2 47 34 Xenia Cooperativa Sociale Onlus \n", + "3 33 20 Xenia Cooperativa Sociale Onlus \n", + "4 14 20 Xenia Cooperativa Sociale Onlus \n", + "5 17 23 Xenia Cooperativa Sociale Onlus \n", + "6 36 23 Xenia Cooperativa Sociale Onlus \n", + "7 18 24 Xenia Cooperativa Sociale Onlus \n", + "8 37 24 Xenia Cooperativa Sociale Onlus \n", + "12 20 7 Xenia Cooperativa Sociale Onlus \n", + "11 1 7 Xenia Cooperativa Sociale Onlus \n", + "9 19 6 Xenia Cooperativa Sociale Onlus \n", + "10 0 6 Xenia Cooperativa Sociale Onlus \n", + "13 38 25 Xenia Cooperativa Sociale Onlus \n", + "14 15 21 Xenia Cooperativa Sociale Onlus \n", + "15 34 21 Xenia Cooperativa Sociale Onlus \n", + "16 45 32 Xenia Cooperativa Sociale Onlus \n", + "17 28 15 Xenia Cooperativa Sociale Onlus \n", + "18 9 15 Xenia Cooperativa Sociale Onlus \n", + "19 50 37 Xenia Cooperativa Sociale Onlus \n", + "20 31 18 Xenia Cooperativa Sociale Onlus \n", + "21 12 18 Xenia Cooperativa Sociale Onlus \n", + "22 25 12 Xenia Cooperativa Sociale Onlus \n", + "23 6 12 Xenia Cooperativa Sociale Onlus \n", + "25 7 13 Xenia Cooperativa Sociale Onlus \n", + "24 26 13 Xenia Cooperativa Sociale Onlus \n", + "26 48 35 Xenia Cooperativa Sociale Onlus \n", + "27 39 26 Xenia Cooperativa Sociale Onlus \n", + "28 49 36 Xenia Cooperativa Sociale Onlus \n", + "29 42 29 Xenia Cooperativa Sociale Onlus \n", + "30 23 10 Xenia Cooperativa Sociale Onlus \n", + "31 4 10 Xenia Cooperativa Sociale Onlus \n", + "32 29 16 Xenia Cooperativa Sociale Onlus \n", + "33 10 16 Xenia Cooperativa Sociale Onlus \n", + "34 40 27 Xenia Cooperativa Sociale Onlus \n", + "35 51 38 Xenia Cooperativa Sociale Onlus \n", + "37 21 8 Xenia Cooperativa Sociale Onlus \n", + "36 2 8 Xenia Cooperativa Sociale Onlus \n", + "39 44 31 Xenia Cooperativa Sociale Onlus \n", + "38 43 30 Xenia Cooperativa Sociale Onlus \n", + "40 24 11 Xenia Cooperativa Sociale Onlus \n", + "41 5 11 Xenia Cooperativa Sociale Onlus \n", + "42 46 33 Xenia Cooperativa Sociale Onlus \n", + "43 11 17 Xenia Cooperativa Sociale Onlus \n", + "44 30 17 Xenia Cooperativa Sociale Onlus \n", + "45 32 19 Xenia Cooperativa Sociale Onlus \n", + "46 13 19 Xenia Cooperativa Sociale Onlus \n", + "47 41 28 Xenia Cooperativa Sociale Onlus \n", + "48 27 14 Xenia Cooperativa Sociale Onlus \n", + "49 8 14 Xenia Cooperativa Sociale Onlus \n", + "50 22 9 Xenia Cooperativa Sociale Onlus \n", + "51 3 9 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "0 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "1 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "2 Bolzano, Via Buozzi,14, Xenia (aziendale) DI PASQUALE ESTHER \n", + "3 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "4 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "5 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "6 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "7 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "8 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NICOL \n", + "11 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO NOCOL \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) PILATO MARTIN \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "15 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) OBKIRCHER REBECCA \n", + "17 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "18 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "19 Bolzano, Via Buozzi,14, Xenia (aziendale) TOKA BREDLEY \n", + "20 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "21 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "22 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "23 Bolzano, Via Buozzi,14, Xenia (aziendale) FERRARESE LEONARDO \n", + "25 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "24 Bolzano, Via Buozzi,14, Xenia (aziendale) BURAGLIO NICOL \n", + "26 Bolzano, Via Buozzi,14, Xenia (aziendale) RISO ALICE \n", + "27 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO LOLA \n", + "28 Bolzano, Via Buozzi,14, Xenia (aziendale) CHIFU SERENA \n", + "29 Bolzano, Via Buozzi,14, Xenia (aziendale) CASTIONI MICHELE \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "31 Bolzano, Via Buozzi,14, Xenia (aziendale) TURANI NINA \n", + "32 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "33 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ EDUART \n", + "35 Bolzano, Via Buozzi,14, Xenia (aziendale) TUTZER SOPHIE \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) OIENI GIADA \n", + "39 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA MICHAEL \n", + "38 Bolzano, Via Buozzi,14, Xenia (aziendale) PISCULA DAVID \n", + "40 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "41 Bolzano, Via Buozzi,14, Xenia (aziendale) MAXIMILIAN COCCO PAOLO \n", + "42 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHULLIAN FELIZIA \n", + "43 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "44 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "45 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "46 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "47 Bolzano, Via Buozzi,14, Xenia (aziendale) VRENJO DEA \n", + "48 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "49 Bolzano, Via Buozzi,14, Xenia (aziendale) MAYR DUFFEK VINCENT \n", + "50 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "51 Bolzano, Via Buozzi,14, Xenia (aziendale) SCAFAR VIKTORIA \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "0 aziendale NaN 01.05.2019 31.08.2022 \n", + "1 aziendale NaN 01.05.2019 31.08.2022 \n", + "2 comunale Laives 01.09.2020 31.08.2022 \n", + "3 aziendale NaN 01.10.2018 31.08.2021 \n", + "4 aziendale NaN 01.10.2018 31.08.2021 \n", + "5 aziendale NaN 02.04.2019 31.08.2020 \n", + "6 aziendale NaN 02.04.2019 31.08.2020 \n", + "7 aziendale NaN 02.09.2019 31.08.2021 \n", + "8 aziendale NaN 02.09.2019 31.08.2021 \n", + "12 comunale Laives 02.10.2017 27.07.2020 \n", + "11 comunale Laives 02.10.2017 27.07.2020 \n", + "9 comunale Laives 02.10.2017 27.07.2020 \n", + "10 comunale Laives 02.10.2017 27.07.2020 \n", + "13 aziendale NaN 03.01.2020 31.08.2021 \n", + "14 aziendale NaN 03.02.2019 08.02.2021 \n", + "15 aziendale NaN 03.02.2019 08.02.2021 \n", + "16 comunale Cornedo all'Isarco 03.06.2020 31.08.2022 \n", + "17 aziendale NaN 05.07.2018 31.08.2020 \n", + "18 aziendale NaN 05.07.2018 31.08.2020 \n", + "19 comunale Laives 05.10.2020 31.12.2021 \n", + "20 aziendale NaN 06.09.2018 30.09.2020 \n", + "21 aziendale NaN 06.09.2018 30.09.2020 \n", + "22 comunale Laives 07.01.2019 31.08.2021 \n", + "23 comunale Laives 07.01.2019 31.08.2021 \n", + "25 comunale Laives 07.03.2019 31.08.2021 \n", + "24 comunale Laives 07.03.2019 31.08.2021 \n", + "26 aziendale NaN 07.09.2020 31.08.2021 \n", + "27 aziendale NaN 08.01.2020 31.08.2022 \n", + "28 aziendale NaN 08.09.2020 31.08.2022 \n", + "29 aziendale NaN 10.02.2020 31.06.2022 \n", + "30 comunale Vadena 10.09.2018 31.08.2020 \n", + "31 comunale Vadena 10.09.2018 31.08.2020 \n", + "32 aziendale NaN 11.12.2017 31.08.2020 \n", + "33 aziendale NaN 11.12.2017 31.08.2020 \n", + "34 aziendale NaN 13.01.2020 31.12.2020 \n", + "35 aziendale NaN 15.11.2020 31.08.2021 \n", + "37 comunale Lana 16.08.2018 31.08.2020 \n", + "36 comunale Lana 16.08.2018 31.08.2020 \n", + "39 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "38 comunale Cornedo all'Isarco 17.02.2020 31.08.2022 \n", + "40 comunale Merano 17.09.2018 31.08.2020 \n", + "41 comunale Nalles 17.09.2018 31.08.2020 \n", + "42 aziendale NaN 20.08.2020 31.08.2023 \n", + "43 aziendale NaN 23.08.2018 31.08.2021 \n", + "44 aziendale NaN 23.08.2018 31.08.2021 \n", + "45 aziendale NaN 26.11.2018 31.08.2020 \n", + "46 aziendale NaN 26.11.2018 31.08.2020 \n", + "47 aziendale NaN 27.01.2020 31.06.2021 \n", + "48 comunale Tesimo 27.05.2019 31.08.2021 \n", + "49 comunale Tesimo 27.05.2019 31.08.2021 \n", + "50 comunale Laives 27.08.2018 31.08.2020 \n", + "51 comunale Laives 27.08.2018 31.08.2020 " + ] + }, + "execution_count": 209, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd1e563f", + "metadata": {}, + "outputs": [], + "source": [ + "df1[\"ore666\"] = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2efa6f7", + "metadata": {}, + "outputs": [], + "source": [ + "df1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5416ddec", + "metadata": {}, + "outputs": [], + "source": [ + "df2[\"DataFine\"].dt.strftime('%m/%d/%Y')" + ] + }, + { + "cell_type": "code", + "execution_count": 282, + "id": "c499fea1", + "metadata": {}, + "outputs": [], + "source": [ + "del df2" + ] + }, + { + "cell_type": "code", + "execution_count": 283, + "id": "068a705b", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'df2' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [283]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf2\u001b[49m\n", + "\u001b[0;31mNameError\u001b[0m: name 'df2' is not defined" + ] + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": 285, + "id": "92273887", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['index', 'Ente', 'Microstruttura', 'Cognome', 'Nome', 'utente',\n", + " 'ComuneProvenienza', 'DataInizio', 'DataFine'],\n", + " dtype='object')" + ] + }, + "execution_count": 285, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c18559e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 287, + "id": "61c75dfe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/home/stfz/notebooks/max/pages/Jupyter'" + ] + }, + "execution_count": 287, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pwd" + ] + }, + { + "cell_type": "code", + "execution_count": 289, + "id": "3166175f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/stfz/notebooks/max\n" + ] + } + ], + "source": [ + "cd .." + ] + }, + { + "cell_type": "code", + "execution_count": 290, + "id": "2261bc84", + "metadata": {}, + "outputs": [], + "source": [ + "dfg = pd.read_excel(\"GemeindenComuni.xlsx\")" + ] + }, + { + "cell_type": "code", + "execution_count": 293, + "id": "ff252390", + "metadata": {}, + "outputs": [], + "source": [ + "c1 = dfx[\"ComuneProvenienza\"].isin(dfg[\"Gemeinde\"])\n", + "c2 = dfx[\"ComuneProvenienza\"].isin(dfg[\"Comune\"])\n", + "c = c1 | c2" + ] + }, + { + "cell_type": "code", + "execution_count": 294, + "id": "72f08d92", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16 False\n", + "14 False\n", + "36 False\n", + "37 False\n", + "0 True\n", + "34 False\n", + "9 False\n", + "12 False\n", + "6 True\n", + "7 True\n", + "4 True\n", + "10 False\n", + "21 True\n", + "5 True\n", + "30 False\n", + "13 False\n", + "8 True\n", + "3 True\n", + "Name: ComuneProvenienza, dtype: bool" + ] + }, + "execution_count": 294, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "c" + ] + }, + { + "cell_type": "code", + "execution_count": 295, + "id": "44ae9143", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
indexEnteMicrostrutturaCognomeNomeutenteComuneProvenienzaDataInizioDataFine
1622Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEQIRAJKLARAaziendaleNaN01.05.201931.08.2022
1420Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)NOMANSOFIAaziendaleNaN01.10.201831.08.2021
3623Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BEZZIGABRIELaziendaleNaN02.04.201931.08.2020
3724Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)SCHMITTNERRAPHAELaziendaleNaN02.09.201931.08.2021
3421Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ER RQXQRAZANaziendaleNaN03.02.201908.02.2021
915Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)TARGAMATILDEaziendaleNaN05.07.201831.08.2020
1218Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)INNEREBNERMIAaziendaleNaN06.09.201830.09.2020
1016Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)COLLATUZZOTOMMASOaziendaleNaN11.12.201731.08.2020
3017Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)ISSAMMLAMRIaziendaleNaN23.08.201831.08.2021
1319Xenia Cooperativa Sociale OnlusBolzano, Via Buozzi,14, Xenia (aziendale)BATTAN BRYANLORENZOaziendaleNaN26.11.201831.08.2020
\n", + "
" + ], + "text/plain": [ + " index Ente \\\n", + "16 22 Xenia Cooperativa Sociale Onlus \n", + "14 20 Xenia Cooperativa Sociale Onlus \n", + "36 23 Xenia Cooperativa Sociale Onlus \n", + "37 24 Xenia Cooperativa Sociale Onlus \n", + "34 21 Xenia Cooperativa Sociale Onlus \n", + "9 15 Xenia Cooperativa Sociale Onlus \n", + "12 18 Xenia Cooperativa Sociale Onlus \n", + "10 16 Xenia Cooperativa Sociale Onlus \n", + "30 17 Xenia Cooperativa Sociale Onlus \n", + "13 19 Xenia Cooperativa Sociale Onlus \n", + "\n", + " Microstruttura Cognome Nome \\\n", + "16 Bolzano, Via Buozzi,14, Xenia (aziendale) BEQIRAJ KLARA \n", + "14 Bolzano, Via Buozzi,14, Xenia (aziendale) NOMAN SOFIA \n", + "36 Bolzano, Via Buozzi,14, Xenia (aziendale) BEZZI GABRIEL \n", + "37 Bolzano, Via Buozzi,14, Xenia (aziendale) SCHMITTNER RAPHAEL \n", + "34 Bolzano, Via Buozzi,14, Xenia (aziendale) ER RQXQ RAZAN \n", + "9 Bolzano, Via Buozzi,14, Xenia (aziendale) TARGA MATILDE \n", + "12 Bolzano, Via Buozzi,14, Xenia (aziendale) INNEREBNER MIA \n", + "10 Bolzano, Via Buozzi,14, Xenia (aziendale) COLLATUZZO TOMMASO \n", + "30 Bolzano, Via Buozzi,14, Xenia (aziendale) ISSAMM LAMRI \n", + "13 Bolzano, Via Buozzi,14, Xenia (aziendale) BATTAN BRYAN LORENZO \n", + "\n", + " utente ComuneProvenienza DataInizio DataFine \n", + "16 aziendale NaN 01.05.2019 31.08.2022 \n", + "14 aziendale NaN 01.10.2018 31.08.2021 \n", + "36 aziendale NaN 02.04.2019 31.08.2020 \n", + "37 aziendale NaN 02.09.2019 31.08.2021 \n", + "34 aziendale NaN 03.02.2019 08.02.2021 \n", + "9 aziendale NaN 05.07.2018 31.08.2020 \n", + "12 aziendale NaN 06.09.2018 30.09.2020 \n", + "10 aziendale NaN 11.12.2017 31.08.2020 \n", + "30 aziendale NaN 23.08.2018 31.08.2021 \n", + "13 aziendale NaN 26.11.2018 31.08.2020 " + ] + }, + "execution_count": 295, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx[~c]" + ] + }, + { + "cell_type": "code", + "execution_count": 298, + "id": "ddad26b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 False\n", + "1 False\n", + "2 False\n", + "3 False\n", + "4 False\n", + " ... \n", + "111 False\n", + "112 False\n", + "113 False\n", + "114 False\n", + "115 False\n", + "Name: Gemeinde, Length: 116, dtype: bool" + ] + }, + "execution_count": 298, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfg[\"Gemeinde\"] == \"Neumarkt\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "accbf103", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/README.md b/pages/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b86c448951a2fbbf34abd597cb344854604e50a8 --- /dev/null +++ b/pages/README.md @@ -0,0 +1 @@ +# max diff --git a/pages/TM_TraegerMitKodex.xlsx b/pages/TM_TraegerMitKodex.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bd2850636ab486decdbf1aaedf56c3daa0a5f3d1 Binary files /dev/null and b/pages/TM_TraegerMitKodex.xlsx differ diff --git "a/pages/TagesMu\314\210tter.py.pevious" "b/pages/TagesMu\314\210tter.py.pevious" new file mode 100644 index 0000000000000000000000000000000000000000..ba939f5cde4cc4fde7cf5e0ed8aa63b9b5b0e9fa --- /dev/null +++ "b/pages/TagesMu\314\210tter.py.pevious" @@ -0,0 +1,2781 @@ +# from curses import ERR +from ast import Pass +from os import path +from unicodedata import numeric + +# from unicodedata import name +# "pippo" +import numpy as np +import pandas as pd + +import copy + +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +from datetime import date + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" # 👽 +) + + +COSTANTI2020 = { + "DATAINIZIOMINIMA": pd.to_datetime("18.05.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MIN": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "DATAFINEMASSIMA": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "ORE2020": 1920, + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "EINGEWÖHNUNG_DATAINIZIO_MIN": pd.to_datetime("13.02.2020", format="%d.%m.%Y"), + "EINGEWÖHNUNG_DATAINIZIO_MAX": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "KONTROLLECOVID_DATAINIZIOASSISTENZA": pd.to_datetime( + "05.03.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID_DATAFINEASSISTENZA2": pd.to_datetime( + "30.10.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID2_DATAINIZIOASSISTENZA": pd.to_datetime( + "24.11.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN": pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX": pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" + ), +} + +COSTANTI2021 = { + "COVID4_DATAINIZIO_MIN": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("28.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MIN": pd.to_datetime("08.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MAX": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), +} + +COSTANTI = {"2020": COSTANTI2020, "2021": COSTANTI2021} +# riferimento centrale e unico per la gestione dei controlli + +ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + # "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Errore dati 543", + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreFinanziamentoCompensativo": "Finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Finanziamento compensativo #2", + "errErroreCovid": "Covid #1", + "errErroreCovid2": "Covid #2", + "errErroreCovid3": "Covid #3", + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung": "Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Ambientamento servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errMassimo543": "Valore massimo ore 543", + "errSommaOre": "Tabella ore per ente gestore", + "errMassimoFC": "Valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella numero bambini per comune e fase", # ok + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", +} + +ERRORDICT2021 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + #"errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella numero bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", +} + + +ERRORDICT = {"2020": ERRORDICT2020, "2021": ERRORDICT2021} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT[ANNORIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + if ANNORIFERIMENTO == "2020": + NO_ZERO = df["Ore totali rendicontate per il 2020"].astype("float") > 0 + elif ANNORIFERIMENTO == "2021": + NO_ZERO = df["Ore totali rendicontate per il 2021"].astype("float") > 0 + + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # st.info(funzione) + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +# START CHECKS + +def errSommaOre666_1025(df): + #df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] = df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"].astype(float) + # df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"] = df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"].astype(float) + # df["Ore totali rendicontate per il 2021"] = df["Ore totali rendicontate per il 2021"].astype(float) + + condizione = (df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] + df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"]) != df["Ore totali rendicontate per il 2021"] #.astype(int) + if not df[condizione].empty: + expndr = st.expander("Tabella con errori riscontrati per somma ore 666 e ore 1025") + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + make_grid(df[condizione], "errSomme666_1025") + df.loc[condizione, "errSomme666_1025"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + "errSomme666_1025", + ) + return df + + + + +def errCalcoloNumeroBimbi(df): + # versione 2020 + #st.write(df) + df = df.reset_index(drop=True) + if ANNORIFERIMENTO == "2020": + + df1 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + elif ANNORIFERIMENTO == "2021": + #dfx = + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + df1025 = pd.DataFrame(columns = ["Comune", "Cognome e nome bambino","Codice fiscale", "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"]) + df666 = pd.DataFrame(columns = ["Comune", "Cognome e nome bambino","Codice fiscale", "Ore di assistenza \n ai sensi della delibera\nn. 666/2019"]) + #iteriamo tutti i record del df controllando che 1025 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in df.index: + if df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"][ind] > 0: + if df1025.empty: + df1025 = df.loc[[ind]] + + else: + # se il codfisc e' gia' presente, passa al prossimo record + # cosi' evitiamo doppioni + if df["Codice fiscale"][ind] in df1025["Codice fiscale"].values: + continue + df1025 = pd.concat([df1025, df.loc[[ind]]]) + + + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in df.index: + if df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"][ind] > 0: + if df666.empty: + df666 = df.loc[[ind]] + else: + # se il codfisc e' gia' presente, passa al prossimo record + # cosi' evitiamo doppioni + if df["Codice fiscale"][ind] in df666["Codice fiscale"].values: + continue + df666 = pd.concat([df666, df.loc[[ind]]]) + + + df1 = df.groupby("Comune", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + + + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + # df2 = df666.groupby("Comune", as_index=False)[ + # "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + # ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + df2 = df.groupby(["Comune"]).agg({"Ore di assistenza \n ai sensi della delibera\nn. 666/2019":"count"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + + + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + + df3 = df1025.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + df3bis = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = df.groupby("Comune", as_index=False)[ + "Ore totali rendicontate per il 2021" + ].apply(lambda x: x[x > 0].sum()) + + + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Somma Giorni Assistenza Anno Riferimento " + ANNORIFERIMENTO, + "Conteggio Nr. bimbi ore 666", + "Somma Ore Assistenza 666", + "Conteggio Nr. bimbi ore 1025", + "Somma Ore Assistenza 1025", + "Ore totali rendicontate per il 2021" + + + # "Nr. bimbi ore rendicontate", + ] + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + gridOptions = buildGrid(dfx) + + + dfx = dfx.append({"Comune": " "}, ignore_index=True) # riga vuota + dfx = dfx.append( + { + "Comune": "file generato in data: " + date.today().strftime("%d/%m/%Y") + }, + ignore_index=True, + ) + + #make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + dfx, + "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + "soloerrori", + ) + + return df + + +def errCalcoloSomme(df): + df_somme = df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + make_grid(df_somme, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE PER COMUNE", + "errCalcoloSomme", + ) + + return df + else: + return df + + +def errSommaOre(df): + #st.write(df) + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"] = df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020"].astype("float") + df_somme = df.groupby("Ente", as_index=False).sum(numeric_only=True) + #st.write(df_somme.columns) + if not df_somme.empty: + #st.write(df_somme) + #df_somme.drop(["Cognome e nome bambino"], axis=1,inplace=True) + # , "Comune di residenza assistente domiciliare all'infanzia", "Data inizio contratto (o data inizio assistenza se diversa) + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + #df_somme = drop_columns(df_somme) + make_grid(df_somme, "errSommaOrex") + #df_somme = df_somme.append({"Ente": " "}, ignore_index=True) # riga vuota + #df_somme = df_somme.append( + # { + # "Ente": "file generato in data: " + date.today().strftime("%d/%m/%Y") + # }, + # ignore_index=True, + #) + + #gridOptions = buildGrid(df_somme) + #AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il " + ANNORIFERIMENTO] == 0 + condizione_logica = condizione & NO_ZERO + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + + df_soli_errori = pd.DataFrame() + df=df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if ANNORIFERIMENTO == "2021": + for ind in df.index: + # st.warning("ind= " + str(ind) + "--> " + df["Comune di residenza assistente domiciliare all'infanzia"][ind]) + if df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + elif ANNORIFERIMENTO == "2020": + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO][ + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN" + ] + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= COSTANTI[ANNORIFERIMENTO][ + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX" + ] + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + x = dwnld( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + # return df + # se non trovato errore il df è restituito come è stato ricevuto + # else: + return df + + +def errDateAnnoRiferimento(df): + condizione_anno_inizio = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.year > int(ANNORIFERIMENTO) + condizione_anno_fine = df["Data fine contratto\n(o data fine assistenza se diversa) *"].dt.year < int(ANNORIFERIMENTO) + + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato {len(df[condizione_logica])} incongruenze data inizio o data fine in relazione ad anno di riferimento (data inizio > anno riferimento oppure data fine < anno riferimento)") + with expndr: + st.info("Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), "errIncongruenzaDateAnnoRiferimento",) + df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON INCONGRUENZE data inizio o fine per anno riferimento", + "errDateAnnoRiferimento",) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + # st.write(dfcod) + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + #st.write(dfnot40) + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"]), "errCodFisc2x") + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +# def errErrorePresenza(df): +# # condizione logica +# ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 +# condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO## + +# if not df[condizione_logica].empty: +# expndr = st.expander( +# f"Trovato errore presenza ({len(df[condizione_logica])} errori)" +# ) +# with expndr: +# st.info( +# "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" +# ) +# make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) +# # settiamo la colonna bool +# df.loc[condizione_logica, "errErrorePresenza"] = True +# x = dwnld( +# df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), +# "Scaricare tabella con errore presenzae", +# "ErrorePresenza", +# )# + +# return df +# # se non trovato errore il df è restituito come è stato ricevuto +# else: +# return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errAgeChildx", + ) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > COSTANTI[ANNORIFERIMENTO]["DATAINIZIOMINIMA"] + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < COSTANTI[ANNORIFERIMENTO]["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errErroreDati543x", + ) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errFineAssistenzaMax4Annix", + ) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = ( + df["Data di nascita"] + <= COSTANTI[ANNORIFERIMENTO]["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > COSTANTI[ANNORIFERIMENTO]["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errKindergarten_1x", + ) + df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = ( + df["Data di nascita"] + >= COSTANTI[ANNORIFERIMENTO]["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + # escluso per il 2021 + #data_nascita2 = df["Data di nascita"] < pd.to_datetime( + # "01.01.2018", format="%d.%m.%Y" + #) + + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + # esculso per il 2021: + # condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errKindergarten_2x", + ) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= COSTANTI[ANNORIFERIMENTO]["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errErroreFinanziamentoCompensativo2x", + ) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO]["DATAFINEMASSIMA"] + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errErroreFinanziamentoCompensativox", + ) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO]["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= COSTANTI[ANNORIFERIMENTO]["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnungx", + ) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO]["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= COSTANTI[ANNORIFERIMENTO]["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnung543Lockdownx", + ) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < COSTANTI[ANNORIFERIMENTO]["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errErroreCovidx", + ) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO]["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid2x", + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= COSTANTI[ANNORIFERIMENTO]["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= COSTANTI[ANNORIFERIMENTO]["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid3x", + ) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + df_soli_errori = pd.DataFrame() + df = df.reset_index(drop=True) + # VERSIONE PER 2021 + if ANNORIFERIMENTO == "2021": + + for ind in df.index: + if df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + + elif df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + + else: + if ( + df["Data inizio contratto (o data inizio assistenza se diversa)"][ + ind + ] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = df.loc[[ind]] + + elif ANNORIFERIMENTO == "2020": + + covid4_datainizio_min = COSTANTI[ANNORIFERIMENTO]["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = COSTANTI[ANNORIFERIMENTO]["COVID4_DATAINIZIO_MAX"] + + # versione per 2020 + + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + x = dwnld( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum(df,): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + # aggiunto 7/10/2022 + # il nr giorni per l'anno di riferimento viene calcolato automaticamente + nrGiorniAnnoRiferimento = pd.Period(ANNORIFERIMENTO+"-12-31", freq='D') + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + + try: + df.to_excel("gesamtstd.xlsx") + except: + st.error("Error writing gesamtstf.xlsx") + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + ANNORIFERIMENTO + ].transform( + "sum" + ).astype( + "float" + ) + + + condizione_logica = condizioneerrore2 & NO_ZERO + + #dfx = df[condizione_logica] + #dfx["Ore fatte"] = (dfx["GiorniAssistenzaAnnoRiferimento"]*1920)/366 + + if not df[condizione_logica].empty: + dfx = df[condizione_logica] + dfx.insert(loc=11, column="Ore calcolate",value = round((dfx["GiorniAssistenzaAnnoRiferimento"]*1920)/nrGiorniAnnoRiferimento,2)) + + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {ANNORIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{ANNORIFERIMENTO}))" + ) + make_grid( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + ANNORIFERIMENTO + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "errMassimo543x", + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not df[cond1 & cond1b & cond1c & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto\n(o data fine assistenza se diversa) *", + ] + - df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not df[cond1 & cond1b & cond1d & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + df.insert(16, "massimofc", 0) + + df["massimofc"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * df["fc"] + + df["massimofc"] = df["massimofc"].astype(int) + + if not df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + make_grid( + df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "errMassimoFCx", + ) + # non settiamo il flag bool perché non ci serve + x = dwnld( + df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo FC calcolato", + "errMassimoFC", + ) + return df + else: + return df + +def errNomeComuneTagesmutter(df): + pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = df["Comune di residenza assistente domiciliare all'infanzia"].isin(dfGemeinden["Gemeinde"]) + condizione2 = df["Comune di residenza assistente domiciliare all'infanzia"].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not df[~condizione].empty: + expndr = st.expander(f"Trovati {len(df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale") + with expndr: + st.info("Elenco delle occorrenze con comune Tagesmutter non corrispondente") + make_grid(df[~condizione].sort_values(by=["filename"]),"errNomeComuneTagesmutterx") + # settiamo il flag bool + df.loc[(~condizione),"errNomeComuneTagesmutter"] = True + + del dfGemeinden + + return df + + + +# FINE CHECKS +################################## + + +def make_grid(dff, k): + # togliamo le colonne bool + dff = drop_columns(dff) + # inseriamo la data di creazione nella prima riga + dff = dff.append({"filename": " "}, ignore_index=True) # riga vuota + dff = dff.append( + { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + }, + ignore_index=True, + ) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + +def get_data(uploaded_files, ANNORIFERIMENTO): + pippo1 = "" + pippo2 = "" + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + contatorefile=0 + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + if ANNORIFERIMENTO == "2020": + df = pd.read_excel(uploaded_file, usecols="A:M") + elif ANNORIFERIMENTO == "2021": + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(uploaded_file, sheet_name="ita", usecols="A:L") + except: + pippo1 = "ita" + pass + try: + df = pd.read_excel(uploaded_file, sheet_name="deu", usecols="A:L") + except: + pippo2 = "deu" + pass + if pippo1 == "ita" and pippo2 == "deu": + st.error(f"file {uploaded_file.name} non ha il foglio con nome o ita o deu") + pippo1="" + pippo2="" + # st.write(df) + except Exception as e: + st.error(uploaded_file.name + " non è un file Excel o non corrisponde alla aspettative") + st.error(e) + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, ANNORIFERIMENTO) + except Exception as e: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione; Errore: {e}" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + contatorefile += 1 + + status.info("") + st.info(f"Vengono usati {contatorefile} per l'elaborazione") + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + # IMPORTANTE!! altrimenti poi ci troviamo indici con lo stesso valore e ci sballa i controlli + # "ambientamento servizio di emergenza" e "inizio contratto durante il servizio di emergenza" + dfout = dfout.reset_index(drop=True) + st.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + if ANNORIFERIMENTO == "2020": + #st.write(dfout) + # ci servono inizializzate per il calcolo delle ore massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + dfout["fc"] = 0 # serve per calcolo massimo finanziamento compensativo + # dfout["covid4_datainizio_min"] = pd.to_datetime('01.01.1970', format="%d.%m.%Y") + # dfout["covid4_datainizio_max"] = pd.to_datetime('01.01.1970', format="%d.%m.%Y") + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT[ANNORIFERIMENTO].keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[ANNORIFERIMENTO][e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, ANNORIFERIMENTO): + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + + if ANNORIFERIMENTO == "2020": + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4].title() + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3].title() + #st.write(gemeinde) + #st.write(traeger) + + elif ANNORIFERIMENTO == "2021": + df.columns = [ + "Numero \nprogressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + # "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2021", + ] + # uniamo cognome e nome + df.insert(1, "Cognome e nome bambino", df["Cognome"] + " " + df["Nome"]) + df.drop(["Cognome", "Nome"], axis=1, inplace=True) + traeger = traeger[0].title() + gemeinde = df.iloc[4] + gemeinde = gemeinde[0].title() + #st.write(gemeinde) + #st.write(traeger) + + gemeindeInserito = gemeinde + + # df["Ore totali rendicontate per il 2021"] = df["Ore totali rendicontate per il 2021"].astype("float") + + + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + if gemeindeInserito not in dfGemeinden["Gemeinde"].unique() and gemeindeInserito not in dfGemeinden["Comune"].unique(): + st.warning(f"L'ente #{traeger}# ha inserito un nome comune non ufficiale: #{gemeindeInserito}#. Il file verra' usato comunque con il comune inserito. Il nome file e': {uploaded_file.name}") + #st.warning(f"") + del dfGemeinden + # st.warning("blocco eseguito") + # st.write(df) + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(ANNORIFERIMENTO) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + df = calcola_giorni_esatti(df) + +# df["GiorniAssistenzaAnnoRiferimento"] = ( +# df["fineNorm"] - df["inizioNorm"] +# ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso +# # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più +# # + return df + +def calcola_giorni_esatti(df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values(by="inizioNorm") #importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + + if DEBUGYES: st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]['inizioNorm'] + latest_enddate = group.iloc[0]['fineNorm'] + + if DEBUGYES: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + #st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if DEBUGYES: st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row['fineNorm'] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row['inizioNorm'] > latest_enddate: + total_effective_days += (latest_enddate - earliest_startdate).days + 1 + earliest_startdate = row['inizioNorm'] + + # Update the latest enddate + latest_enddate = row['fineNorm'] + indx = index + if DEBUGYES: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + #st.error(index) + if DEBUGYES: st.info(f"last index={indx}") + if DEBUGYES: st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + +def drop_columns(df): + + for k in ERRORDICT[ANNORIFERIMENTO]: + df = df.drop([k], axis=1) + + if ANNORIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT[ANNORIFERIMENTO].keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + if ANNORIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + #st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT[ANNORIFERIMENTO]: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[ANNORIFERIMENTO][e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT[ANNORIFERIMENTO]: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[ANNORIFERIMENTO][e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 1.61c)") + global DEBUGYES + DEBUGYES = False #st.sidebar.checkbox("debug da shit") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # ANNORIFERIMENTO = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + global ANNORIFERIMENTO + ANNORIFERIMENTO = st.selectbox("ANNO RIFERIMENTO", ("2021", "2020")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, ANNORIFERIMENTO) + if dfout is not None: + dfout = compute_hours(dfout, ANNORIFERIMENTO) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, key = "tabfinalex" + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + # st.balloons() + + +app() diff --git "a/pages/TagesMu\314\210tterOld.py.bak" "b/pages/TagesMu\314\210tterOld.py.bak" new file mode 100644 index 0000000000000000000000000000000000000000..417ac2bf7162d720847cebd760d575a8a8e4e5b9 --- /dev/null +++ "b/pages/TagesMu\314\210tterOld.py.bak" @@ -0,0 +1,1868 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +from datetime import date + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + #"errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Calcolo delle somme ore per comune", + "errCalcoloNumeroBimbi": "Calcolo numero bambini per comune e tipo ore", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +# START CHECKS + + +def errCalcoloNumeroBimbi(df): + df1 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + gridOptions = buildGrid(dfx) + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + dfx, + "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + "soloerrori", + ) + + return df + + +def errCalcoloSomme(df): + df_somme = df.groupby("Comune", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE PER COMUNE", + "errCalcoloSomme", + ) + + return df + else: + return df + + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = condizione & NO_ZERO + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +#def errErrorePresenza(df): +# # condizione logica +# ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 +# condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO## + +# if not df[condizione_logica].empty: +# expndr = st.expander( +# f"Trovato errore presenza ({len(df[condizione_logica])} errori)" +# ) +# with expndr: +# st.info( +# "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" +# ) +# make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) +# # settiamo la colonna bool +# df.loc[condizione_logica, "errErrorePresenza"] = True +# x = dwnld( +# df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), +# "Scaricare tabella con errore presenzae", +# "ErrorePresenza", +# )# + +# return df +# # se non trovato errore il df è restituito come è stato ricevuto +# else: +# return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not df[cond1 & cond1b & cond1c & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto\n(o data fine assistenza se diversa) *", + ] + - df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not df[cond1 & cond1b & cond1d & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + df.insert(16, "massimofc", 0) + + df["massimofc"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * df["fc"] + + df["massimofc"] = df["massimofc"].astype(int) + + if not df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + make_grid( + df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + # non settiamo il flag bool perché non ci serve + x = dwnld( + df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo FC calcolato", + "errMassimoFC", + ) + return df + else: + return df + + +# FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + # inseriamo la data di creazione nella prima riga + dff = dff.append({"Cognome e nome bambino": " "}, ignore_index=True) # riga vuota + dff = dff.append( + { + "Comune di residenza assistente domiciliare all'infanzia": "file creato il:", + "Data inizio contratto (o data inizio assistenza se diversa)": date.today().strftime( + "%d/%m/%Y" + ), + }, + ignore_index=True, + ) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + dfout["fc"] = 0 # server per calcolo massimo finanziamento compensativo + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=False) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 1.0.1)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + # st.balloons() + + +app() diff --git "a/pages/TagesMu\314\210tter_ver.2.py.bak" "b/pages/TagesMu\314\210tter_ver.2.py.bak" new file mode 100644 index 0000000000000000000000000000000000000000..d3fecb9b16106f4fc8d79fe7bd03db6c7d3a0888 --- /dev/null +++ "b/pages/TagesMu\314\210tter_ver.2.py.bak" @@ -0,0 +1,3078 @@ +from distutils import filelist +from os import path +from unicodedata import numeric +import numpy as np +import pandas as pd +import copy +import xlsxwriter +import streamlit as st +import streamlit_ext as ste # cerchiamo di fare in modo che rimanga una soluzione temporanea +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d +from datetime import date, datetime +import io + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗" +) # 👽9 + + +class valoriEtErrori: + COSTANTI2020 = { + "DATAINIZIOMINIMA": pd.to_datetime("18.05.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MIN": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "DATAFINEMASSIMA": pd.to_datetime("17.05.2020", format="%d.%m.%Y"), + "ORE2020": 1920, + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "EINGEWÖHNUNG_DATAINIZIO_MIN": pd.to_datetime("13.02.2020", format="%d.%m.%Y"), + "EINGEWÖHNUNG_DATAINIZIO_MAX": pd.to_datetime("05.03.2020", format="%d.%m.%Y"), + "KONTROLLECOVID_DATAINIZIOASSISTENZA": pd.to_datetime( + "05.03.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID_DATAFINEASSISTENZA2": pd.to_datetime( + "30.10.2020", format="%d.%m.%Y" + ), + "KONTROLLECOVID2_DATAINIZIOASSISTENZA": pd.to_datetime( + "24.11.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN": pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" + ), + "KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX": pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" + ), + } + COSTANTI2021 = { + "COVID4_DATAINIZIO_MIN": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "COVID4_DATAINIZIO_MAX": pd.to_datetime("28.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MIN": pd.to_datetime("08.02.2021", format="%d.%m.%Y"), + "543_DATAINIZIO_MAX": pd.to_datetime("22.02.2021", format="%d.%m.%Y"), + "KONTROLLEKINDERGARTEN_DATANASCITA_1": pd.to_datetime( + "28.02.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.03.2017", format="%d.%m.%Y" + ), + "KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2": pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" + ), + } + COSTANTI = {"2020": COSTANTI2020, "2021": COSTANTI2021} + ERRORDICT2020 = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + # "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Errore dati 543", + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreFinanziamentoCompensativo": "Finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Finanziamento compensativo #2", + "errErroreCovid": "Covid #1", + "errErroreCovid2": "Covid #2", + "errErroreCovid3": "Covid #3", + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung": "Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Ambientamento servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errMassimo543": "Valore massimo ore 543", + "errSommaOre": "Tabella ore per ente gestore", + "errMassimoFC": "Valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella numero bambini per comune e fase", # ok + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + ERRORDICT2021 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Fine contratto assistenza", + "errKindergarten_1": "Scuola dell'infanzia #1", # ok + "errKindergarten_2": "Scuola dell'infanzia #2", # ok + "errErroreCovid4": "Inizio contratto durante il servizio di emergenza", # ok + "errFehlerEingewöhnung543Notbetreuung": "Ambientamento servizio di emergenza", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errSommaOre": "Tabella ore per ente gestore", + # "errCalcoloSomme": "Tabella ore per comune e fase", # ok + "errCalcoloNumeroBimbi": "Tabella numero bambini per comune e fase", # ok + "errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + "errSommaOre666_1025": "Controllo somma ore 666 e ore 1025", + } + ERRORDICT = {"2020": ERRORDICT2020, "2021": ERRORDICT2021} + + +class makeInterface: + # st.set_page_config(page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="🤗") # 👽9 + st.markdown("# FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.markdown("## Controllo errori Tagesmütter (v. 2.2.8)") + st.sidebar.markdown(f"### Impostazioni controlli TAGESMÜTTER") + + def __init__(self, valori): + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", ("2020", "2021", "2022", "2023"), index=1 + ) + self.MOSTRAERRORIINTEGRITA = st.sidebar.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.sidebar.checkbox("Convertire le date in stringhe", True) + self.DEBUGWARNINGS = ( + False # st.sidebar.checkbox("Interrompere elaborazione se...") + ) + self.TOLLERANZAZERO = False # st.sidebar.checkbox("Tolleranza zero") + self.INTERRUZIONE = st.sidebar.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + self.DEBUGGENERAL = st.sidebar.checkbox("Debug generale") + self.MOSTRACOSTANTI = st.sidebar.checkbox( + "Mostra costanti per anno riferimento" + ) + if self.MOSTRACOSTANTI: + try: + st.sidebar.info(valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.sidebar.error("Impossibile mostrare costanti") + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + self.choose_files() + self.choose_checks() + + def make_form(self): + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + + def choose_files(self): + self.uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + def choose_checks(self): + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and values. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + self.checks = {} + st.write("") + a = 1 + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrita' dei dati vengono eseguiti sempre)", + expanded=False, + ) + c1, c2, c3, c4 = expndr.columns(4) + + try: + with expndr: + st.write("") + # If the error dictionary is not empty, cioè se esiste + if self.ERRORDICT: + # Create a 'select all' checkbox and set its initial value to True + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + # Loop through each error key-value pair in the error dictionary + for chiave_errore, valore_errore in self.ERRORDICT.items(): + # Create a checkbox for the current error and set its initial value to the 'select all' checkbox value + checkbox_name = f"{chiave_errore}_checkbox" + checkbox_value = locals()[f"{checkbox_name}"] = locals()[ + f"c{a}" + ].checkbox(valore_errore, value=attivatutti, key=chiave_errore) + # If the current checkbox is the 4th one in a row, reset the counter to 1 + if a == 4: + a = 1 + else: + a += 1 + # Add the current error and its checkbox value to the 'checks' dictionary + self.checks[chiave_errore] = checkbox_value + + except Exception as e: + with expndr: + st.warning( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}?" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self): + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + gb.configure_side_bar() + # gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # gb.configure_default_column( + # groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=False + # ) + gridOptions = gb.build() + return gridOptions + + +class trovaErrori: + def __init__(self, df, interface): + self.checks = interface.checks + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.ERRORDICT = valoriEtErrori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.COSTANTI = valoriEtErrori.COSTANTI[self.ANNO_RIFERIMENTO] + self.df = df + self.dffinal = pd.DataFrame + + # let the show start + self.check_data() + + def converti_date_in_stringhe(self, df): + #pass + try: + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"].dt.strftime('%d/%m/%Y') + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + def make_grid(self, dff, k): + dff = self.drop_columns(dff) + # inseriamo la data di creazione nella prima riga + # new_row_data = {"filename": " "} + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + gridOptions = self.buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + def buildGrid(self, data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + gridOptions = gb.build() + return gridOptions + + def drop_columns(self, df): + for k in self.ERRORDICT.keys(): + try: + df = df.drop([k], axis=1) + except Exception as e: + if interface.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop + + if self.ANNO_RIFERIMENTO == "2020": + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + return df + + def dwnld(self, df, k, ff): # questa è la versione più vecchia + if ff != "soloerrori": + df = self.drop_columns(df) + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute!!!!! + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + + def download_excel_file( + self, dftosave, nome_file, flag=None + ): # questa la versione in uso + nome_file = f'{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{nome_file}' + if flag != "casospeciale": + dftosave = self.drop_columns(dftosave) + + writer = pd.ExcelWriter("filetemporaneo.xlsx", engine="xlsxwriter") + workbook = writer.book + worksheet = workbook.add_worksheet("risultato") + for col in range(dftosave.shape[1]): + worksheet.set_column(col, col, 30) + + dftosave.to_excel(writer, sheet_name="risultato", index=False) + writer.close() + with open("filetemporaneo.xlsx", "rb") as f: + file_bytes = f.read() + # usiamo streamlit_ext as ste + ste.download_button( + label="Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + #def prepare_for_excel( + # self, df + #) -> bytes: # non testata del tutto, da chiamare da st.download_button + # output = io.BytesIO() + # writer = pd.ExcelWriter(output, engine="xlsxwriter") + # df.to_excel(writer, sheet_name="Sheet1") + # writer.close() + # processed_data = output.getvalue() + # return processed_data + + def make_df_solo_errori(self): + self.dffinal = self.df + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in self.ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = self.dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | self.dffinal[e] == True + + # creiamo df con soli record con errore + self.dffinal = self.dffinal[condizione] + + if self.ANNO_RIFERIMENTO == "2020": + # droppiamo la colonna che non vogliamo + self.dffinal = self.dffinal.drop(["errMassimo543"], axis=1) + + def genera_report(self): + # genera un report un po' raffazzonato in formato Excel + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = self.df["Codice fiscale"].nunique() + row += 2 + worksheet.write( + row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini" + ) + row += 2 + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + nrerr = len(self.df[condizione]) + if nrerr > 0: + worksheet.write( + row, + col, + f"Trovate {nrerr} occorrenze per il controllo {self.ERRORDICT[e]}", + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + + # start riassunto per tipo errore + for e in self.ERRORDICT: + if e == "errMassimo543": + continue + condizione = self.df[e] == True + df_bambini = self.df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{self.ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.success("Generato file riassunto analisi") + + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + def check_data(self): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + column_name = f"Ore totali rendicontate per il {self.ANNO_RIFERIMENTO}" + NO_ZERO = self.df[column_name].astype("float") > 0 + with interface.TAB2: + for check, enabled in self.checks.items(): + if enabled: + if interface.DEBUGGENERAL: + st.write(check) + # Call the method with the same name as the check. + # I used the 'getattr' function to call the functions in the 'checks' dictionary instead of using 'eval'. + # previous version: eval("self." + tipo_controllo + "()") + try: + # la seguente riga chiama una funzione (controllo errori) + # dopo l'altra, a seconda se è attivata o meno + getattr(self, check)() + except Exception as e: # KeyError: + st.error( + f"La funzione {check} non è stata eseguita; errore {e}." + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + with interface.TAB3: + self.genera_report() + st.write("") + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.df.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.df.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + self.dwnld( + self.df.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + self.make_df_solo_errori() + + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = self.buildGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + self.dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex", + ) + self.dwnld( + self.dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + st.write("") + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # da qui in poi sono i controlli da eseguire + def errCodFisc1(self): + # possono esserci blanks all'inizio e fine + self.df["Codice fiscale"] = self.df["Codice fiscale"].str.strip() + + # definiamo condizione logica per trovare codice fiscale invalido usando regex + codinvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errore_codice_fiscale_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errCodFisc1x", + ) + # settiamo il flag bool per la tabella finale + self.df.loc[condizione_logica, "errCodFisc1"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore codice fiscale", + # "ErroreCodiceFiscale", + # ) + + def errCodFisc2(self): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + self.df["Codice fiscale"].str.match( + r"[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = self.df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[ + 8:9 + ].astype("str").replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale \n\r ATTENZIONE: il bambino occorre piu' volte, a seconda di quanti errori vengono trovati." + ) + + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + results = pd.concat(frames) + if interface.CONVERTIDATESTRINGHE: + results = self.converti_date_in_stringhe(results) + + self.download_excel_file( + results.sort_values(by=["Cognome e nome bambino"]), + "errore_codice_fiscale_2.xlsx", + ) + self.make_grid( + results.sort_values(by=["Cognome e nome bambino"]), "errCodFisc2x" + ) + # settiamo il flag bool per i codfisc che sono presenti in results + self.df.loc[ + self.df["Codice fiscale"].isin(results["Codice fiscale"]), + "errCodFisc2", + ] = True + + def errSommaOre666_1025(self): + condizione = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] + + self.df["Ore di assistenza \n ai sensi della delibera\nn. 666/2019"] + ) != self.df[ + "Ore totali rendicontate per il 2021" + ] # .astype(int) + + if not self.df[condizione].empty: + expndr = st.expander( + "Tabella con errori riscontrati per somma ore 666 e ore 1025" + ) + with expndr: + st.info("Somme ore 666 e ore 1025 incongruente con la somma riportata") + dftemp = self.df[condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_somme_666_e_1025.xlsx" + ) + self.make_grid(dftemp, "errSomme666_1025") + self.df.loc[condizione, "errSomme666_1025"] = True + + # x = self.dwnld( + # self.df[condizione], + # "SCARICARE TABELLA CON ERRORI SOMME ORE 666 e ORE 1025", + # "errSomme666_1025", + # ) + + def errCalcoloNumeroBimbi(self): + # versione 2020 + # st.write(df) + self.df = self.df.reset_index(drop=True) + if self.ANNO_RIFERIMENTO == "2020": + df1 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + elif self.ANNO_RIFERIMENTO == "2021": + # creiamo un df apposta senza codifisc doppi ma controllando che il valore 1025 non sia nullo + df1025 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + ] + ) + df666 = pd.DataFrame( + columns=[ + "Comune", + "Cognome e nome bambino", + "Codice fiscale", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + ] + ) + # iteriamo tutti i record del df controllando che 1025 non sia zero + # e controlliamo che codfisc occorra solo una volta + + #>>> non possiamo usare questa soluzione se il nome della colonna contiene il carattere "nuova riga" + #>>> filtered_df = self.df.eval("`Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020` > 0") + #>>> df1025 = filtered_df.drop_duplicates(subset=["Codice fiscale", "Comune"]) + + for ind in self.df.index: + if ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if df1025.empty: + df1025 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df1025["Codice fiscale"]) + & (self.df["Comune"][ind] == df1025["Comune"]) + ).any(): + df1025 = pd.concat([df1025, self.df.loc[[ind]]]) + else: + continue + + # iteriamo tutti i record del df controllando che 666 non sia zero + # e controlliamo che codfisc occorra solo una volta + for ind in self.df.index: + if ( + self.df[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ][ind] + > 0 + ): + if df666.empty: + df666 = self.df.loc[[ind]] + else: + # se il codfisc e' gia' presente per un dato comune, passa al prossimo record + # cosi' evitiamo doppioni + # soluzione suggerita da gpt4 + if not ( + (self.df["Codice fiscale"][ind] == df666["Codice fiscale"]) + & (self.df["Comune"][ind] == df666["Comune"]) + ).any(): + df666 = pd.concat([df666, self.df.loc[[ind]]]) + else: + continue + + df1 = self.df.groupby("Comune", as_index=False)[ + "GiorniAssistenzaAnnoRiferimento" + ].apply(lambda x: x[x > 0].sum()) + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df.groupby(["Comune"]).agg({"GiorniAssistenzaAnnoRiferimento":"sum"}) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + + # la lambda serve per contare solo valori > 0 - anche se dovrebbe essere inutile + # visto che abbiamo creato il df sopra e abbiamo gia' messo la condizione` + df2 = df666.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0]) + + ################################################## + ######### SI PUO' FARE ANCHE COSI' + # + # df2 = self.df.groupby(["Comune"]).agg( + # {"Ore di assistenza \n ai sensi della delibera\nn. 666/2019": "count"} + # ) + # cfr. https://pbpython.com/groupby-warning.html + # + ################################################## + # la lambda serve per contare solo valori > 0 - qui non e` inutile + df2bis = self.df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].sum()) + + df3 = df1025.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].count() # NON SERVE --> .apply(lambda x: x[x > 0] + + df3bis = self.df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].apply(lambda x: x[x > 0].sum()) + + # qui nessuna condizione + df4 = self.df.groupby("Comune", as_index=False)[ + "Ore totali rendicontate per il 2021" + ].apply(lambda x: x[x > 0].sum()) + + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df2bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df3bis, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Somma Giorni Assistenza Anno Riferimento " + self.ANNO_RIFERIMENTO, + "Conteggio Nr. bimbi ore 666", + "Somma Ore Assistenza 666", + "Conteggio Nr. bimbi ore 1025", + "Somma Ore Assistenza 1025", + "Ore totali rendicontate per il 2021" + # "Nr. bimbi ore rendicontate", + ] + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + + # "casospeciale" perchè passiamo un dataframe appositamente preparato + # che non contiene le colonne bool + + + + riga_vuota = {"Comune": " "} + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + + riga_vuota = { + "Comune": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + nuova_riga_df = pd.DataFrame(riga_vuota, index=[0]) + dfx = pd.concat([dfx, nuova_riga_df], ignore_index=True) + gridOptions = self.buildGrid(dfx) + + self.download_excel_file( + dfx, "calcolo_bimbi_per_tipologia_comune_ore.xlsx", "casospeciale" + ) + # make_grid(dfx, "errcalcolosommeorecomune") + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + + # x = self.dwnld( + # dfx, + # "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + # "soloerrori", + # ) + + def errCalcoloSomme(self): + df_somme1 = self.df.groupby("Comune", as_index=False).sum(numeric_only=True) + if not df_somme1.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + self.download_excel_file(df_somme1, "somme_ore_per_comune.xlsx") + self.make_grid(df_somme1, "errcalcolosommex") + # non settiamo il flag bool perché qui non ci serve + + def errSommaOre(self): + # st.write(df) + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ] = self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ].astype( + "float" + ) + df_somme = self.df.groupby("Ente", as_index=False).sum(numeric_only=True) + # st.write(df_somme.columns) + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme per ente") + with expndr: + st.info("Valori sommati") + self.download_excel_file(df_somme, "somma_ore_per_ente.xlsx") + self.make_grid(df_somme, "errSommaOrex") + + # gridOptions = buildGrid(df_somme) + # AgGrid(df_somme, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + # self.download_excel_file(df_somme,"somma_ore.xlsx") + # x = self.dwnld( + # df_somme, + # "SCARICARE TABELLA CON SOMME DELLE ORE", + # "errSommaOre", + # ) + + def errOreRendicontateZero(self): + condizione = ( + self.df["Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO] == 0 + ) + condizione_logica = condizione & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno {self.ANNO_RIFERIMENTO}" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "ore_rendicontate_zero.xlsx", + ) + self.make_grid( + dftemp.sort_values(by=["Cognome e nome bambino"]), + "errOreRendicontateZerox", + ) + # settiamo la colonna bool + self.df.loc[condizione, "errOreRendicontateZero"] = True + + def errFehlerEingewöhnung543Notbetreuung(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER IL 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("04.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("06.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("01.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + if not df_soli_errori.empty: + df_soli_errori = pd.concat([df_soli_errori, df.loc[[ind]]]) + else: + df_soli_errori = copy.copy(df.loc[[ind]]) + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errFehlerEingewöhnung543Notbetreuung"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = copy.copy(self.df.loc[[ind]]) + + elif self.ANNO_RIFERIMENTO == "2020": + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + ) + + df_soli_errori = df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato errore ambientamento servizio di emergenza ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_eingewoehnung_543_notbetreuung.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errFehlerEingewöhnung543Notbetreuungx", + ) + # settiamo la colonna bool + df_soli_errori["errFehlerEingewöhnung543Notbetreuung"] = True + + def errDateAnnoRiferimento(self): + condizione_anno_inizio = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].dt.year > int(self.ANNO_RIFERIMENTO) + condizione_anno_fine = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].dt.year < int(self.ANNO_RIFERIMENTO) + condizione_logica = (condizione_anno_inizio | condizione_anno_fine) & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato {len(self.df[condizione_logica])} incongruenze data inizio o data fine in relazione all'anno di riferimento (data inizio > {self.ANNO_RIFERIMENTO} oppure data fine < {self.ANNO_RIFERIMENTO}" + ) + with expndr: + st.info( + "Elenco delle righe per cui sono state trovate incongruenze di data inizio o fine con anno di riferimento" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "incongruenze_data_inizio_o_fine_per_anno_riferimento.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errIncongruenzaDateAnnoRiferimento", + ) + self.df.loc[condizione_logica, "errDateAnnoRiferimento"] = True + + def errInizioMinoreFine(self): + inizio_minore_fine = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len( self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_datainizio_maggiore_fine.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errInizioMinoreFinex", + ) + # settiamo la colonna bool + self.df.loc[condizione_logica, "errInizioMinoreFine"] = True + + def errAgeChild(self): + giorni = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + - self.df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eta_bambino.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errAgeChildx", + ) + # settiamo la colonna bool + self.df.loc[ + condizione_logica, + "errAgeChild", + ] = True + + def errErroreDati543(self): + errore_dati_543p1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + > self.COSTANTI["DATAINIZIOMINIMA"] + ) + + errore_dati_543p2 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["DATAFINEMASSIMA"] + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_dati_543.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreDati543x", + ) + self.df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + + def errFineAssistenzaMax4Anni(self): + giorni = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - self.df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_fine_contratto_assistenza_max4anni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFineAssistenzaMax4Annix", + ) + + self.df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + + def errKindergarten_1(self): + data_nascita = ( + self.df["Data di nascita"] + <= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_1"] + ) + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > self.COSTANTI["KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1"] + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_1x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_1x", + ] = True + + def errKindergarten_2(self): + data_nascita = ( + self.df["Data di nascita"] + >= self.COSTANTI["KONTROLLEKINDERGARTEN_DATANASCITA_2"] + ) + + data_fine_ass = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + + (pd.to_datetime(self.df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + + if self.ANNO_RIFERIMENTO == "2020": + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + else: + condizione_logica = data_nascita & data_fine_ass & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_kindergarten_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errKindergarten_2x", + ) + self.df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + + def errErroreFinanziamentoCompensativo2(self): + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["DATAINIZIOMINIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanz_compensativo_2.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativo2x", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + + def errErroreFinanziamentoCompensativo(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["DATAFINEMASSIMA"] + ) + ore_compensative = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_finanziamento_compensativo_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreFinanziamentoCompensativox", + ) + + self.df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + + def errFehlerEingewöhnung(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnungx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + + def errFehlerEingewöhnung543Lockdown(self): + data_inizio_minima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MIN"] + ) + data_inizio_massima = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= self.COSTANTI["EINGEWÖHNUNG_DATAINIZIO_MAX"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_eingewoehnung_543_lockdown.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errFehlerEingewöhnung543Lockdownx", + ) + + self.df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + + def errErroreCovid(self): + data_fine_assistenza = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_1.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovidx", + ) + + self.df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + + def errErroreCovid2(self): + data_inizio_ass = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID2_DATAINIZIOASSISTENZA"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + self.df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione che serve per evitare records con ore rendicontate = 0 + if not self.df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(self.df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + + dftemp = self.df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file(dftemp, "errori_covid_2.xlsx") + self.make_grid(dftemp, "errErroreCovid2x") + self.df.loc[ + dftemp, + "errErroreCovid2", + ] = True + + def errErroreCovid3(self): + data_inizio = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= self.COSTANTI["KONTROLLECOVID_DATAINIZIOASSISTENZA"] + ) + data_fine = ( + self.df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= self.COSTANTI["KONTROLLECOVID_DATAFINEASSISTENZA2"] + ) + ore_543 = ( + self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_covid_3.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errErroreCovid3x", + ) + + self.df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + + def errErroreCovid4(self): + df_soli_errori = pd.DataFrame() + self.df = self.df.reset_index(drop=True) + # VERSIONE PER 2021 + if self.ANNO_RIFERIMENTO == "2021": + for ind in self.df.index: + if self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "merano", + "meran", + "rifiano", + "riffian", + "moso in passiria", + "moso", + "moos in passeier", + "moos", + "s. pancrazio", + "st. pankraz", + "pancrazio", + "pankraz", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("18.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "malles venosta", + "malles", + "mals", + "lana", + "s. martino in passiria", + "s. martino passiria", + "st. martin passeier", + "st. martin in passeier", + "caines", + "kuens", + "s. leonardo in passiria", + "s. leonardo passiria", + "st. leonhard in passeier", + "st. leonhard in pass.", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("20.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "tirolo", + "tirol", + "silandro", + "schlanders", + "parcines", + "partschins", + ): + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ("scena", "schenna"): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("02.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("07.03.2021", format="%d.%m.%Y") + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.df["Comune di residenza assistente domiciliare all'infanzia"][ + ind + ].lower() in ( + "lagundo", + "algund", + "tubre", + "taufers im münstertal", + "glorenza", + "glurns", + ): + if ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + ) + or ( + ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("08.03.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("14.03.2021", format="%d.%m.%Y") + ) + ) + ) and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ + ind + ] > 0: + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + else: + if ( + self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + >= pd.to_datetime("22.02.2021", format="%d.%m.%Y") + and self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ][ind] + <= pd.to_datetime("28.02.2021", format="%d.%m.%Y") + and self.df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020" + ][ind] + > 0 + ): + self.df["errErroreCovid4"][ind] = True + if not df_soli_errori.empty: + df_soli_errori = pd.concat( + [df_soli_errori, self.df.loc[[ind]]] + ) + else: + df_soli_errori = self.df.loc[[ind]] + + elif self.ANNO_RIFERIMENTO == "2020": + covid4_datainizio_min = self.COSTANTI["COVID4_DATAINIZIO_MIN"] + covid4_datainizio_max = self.COSTANTI["COVID4_DATAINIZIO_MAX"] + condizione1 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= covid4_datainizio_min + ) + condizione2 = ( + self.df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= covid4_datainizio_max + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + df_soli_errori = self.df[condizione_logica] + + if not df_soli_errori.empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df_soli_errori)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui è soddisfatta la condizione di errore in base alla data inizio a seconda del comune" + ) + + if interface.CONVERTIDATESTRINGHE: + df_soli_errori = self.converti_date_in_stringhe(df_soli_errori) + + self.download_excel_file( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errori_covid_4.xlsx", + ) + self.make_grid( + df_soli_errori.sort_values(by=["Cognome e nome bambino"]), + "errErroreCovid4x", + ) + + df_soli_errori["errErroreCovid4"] = True + + def errGesamtstundenVertragszeitraum( + self, + ): + nrGiorniAnnoRiferimento = pd.Period(self.ANNO_RIFERIMENTO + "-12-31", freq="D") + nrGiorniAnnoRiferimento = nrGiorniAnnoRiferimento.day_of_year + +# try: +# # non facciamo altro che salvare il file in caso di problemi +# self.df.to_excel("gesamtstd.xlsx") +# except Exception as e: +# st.error(f"Error writing gesamtstf.xlsx; errore {e}") +# if interface.TOLLERANZAZERO: +# st.error("ELaborazione terminata") +# st.stop() + + condizioneerrore2 = ( + ( + 1920 + * ( + self.df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / nrGiorniAnnoRiferimento # ATTENZIONE: 365 SOLO se NON e' anno bisestile + ) + ) < self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ].transform( + "sum" + ).astype( + "float" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not self.df[condizione_logica].empty: + dfx = self.df[condizione_logica] + dfx.insert( + loc=11, + column="Ore calcolate", + value=round( + (dfx["GiorniAssistenzaAnnoRiferimento"] * 1920) + / nrGiorniAnnoRiferimento, + 2, + ), + ) + + expndr = st.expander( + f"Trovato errore Proportion Maximalstunden überschritten (trovati {len(dfx)} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il {self.ANNO_RIFERIMENTO}. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/{nrGiorniAnnoRiferimento}) < (oreTotaliRendicontate{self.ANNO_RIFERIMENTO}))" + ) + if interface.CONVERTIDATESTRINGHE: + dfx = self.converti_date_in_stringhe(dfx) + + self.download_excel_file( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errori_giorni_assistenza_inferiori_somma_ore_rendicontate.xlsx", + ) + self.make_grid( + dfx.sort_values(by=["Cognome e nome bambino"]), + "errGesamtstundenVertragszeitraumx", + ) + + # settiamo il flag bool per la tabella finale + self.df.loc[ + condizione_logica, "errGesamtstundenVertragszeitraum" + ] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive per durata contrattuale", + # "ErroreOreComplessive", + # ) + + def errSuperatoOreMassime1920(self): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + self.df.groupby("Codice fiscale")[ + "Ore totali rendicontate per il " + self.ANNO_RIFERIMENTO + ] + .transform("sum") + .astype("float") + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + # c1, c2 = st.columns(2) + st.info( + f"Elenco dei bambini per cui la somma delle ore totali rendicontate per il {self.ANNO_RIFERIMENTO} è maggiore di 1920" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + x = self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_ore_complessive_maggiore_1920.xlsx", + ) + + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errSuperatoOreMassime1920x", + ) + + # settiamo flag per tabella finale + self.df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con errore ore complessive maggiore 1920", + # "ErroreOre1920", + # ) + + def errBambinoInPiuComuni(self): + condizionlogica1 = ( + self.df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + ) + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + dftemp = self.df[condizione_logica] + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_in_piu_comuni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errBambinoInPiuComunix", + ) + + # settiamo flag bool per tabella finale + self.df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini in più comuni", + # "errBambinoInPiuComuni", + # ) + + def errPresentiAnnotazioni(self): + condizione = ( + self.df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") + == True + ) + condizione_logica = condizione & NO_ZERO + + if not self.df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(self.df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + dftemp = self.df[condizione_logica] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errori_bambini_con_annotazioni.xlsx", + ) + self.make_grid( + dftemp.sort_values( + by=["Cognome e nome bambino"] + ), + "errPresentiAnnotazionix", + ) + + # settiamo flag bool + self.df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + + # x = self.dwnld( + # self.df[condizione_logica].sort_values( + # by=["Cognome e nome bambino"] + # ), + # "Scaricare tabella con bambini con annotazioni", + # "errPresentiAnnotazioni", + # ) + + def errMassimo543(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | self.df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not self.df[cond1 & cond1b & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + self.df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not self.df[cond2 & cond2b & NO_ZERO].empty: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + self.df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not self.df[cond3 & cond3b & cond3c & NO_ZERO].empty: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + self.df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + self.df.insert(13, "massimo543", 0) + + self.df["massimo543"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * (self.df["gg1"] + self.df["gg2"] + self.df["gg3"]) + + self.df["massimo543"] = self.df["massimo543"].astype(int) + + if not self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(self.df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + dftemp = self.df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_543_calcolato.xlsx" + ) + + self.make_grid(dftemp,"errMassimo543x",) + + # settiamo flag bool + self.df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + + # x = self.dwnld( + + # , + # "Scaricare tabella con bambini con valore massimo 543 calcolato", + # "errMassimo543", + # ) + + def errMassimoFC(self): + cond1 = self.df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = self.df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not self.df[cond1 & cond1b & cond1c & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = ( + self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data fine contratto\n(o data fine assistenza se diversa) *", + ] + - self.df.loc[ + cond1 & cond1b & cond1c & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + if not self.df[cond1 & cond1b & cond1d & NO_ZERO].empty: + self.df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = ( + pd.to_datetime("31.08.2020", format="%d.%m.%Y") + - self.df.loc[ + cond1 & cond1b & cond1d & NO_ZERO, + "Data inizio contratto (o data inizio assistenza se diversa)", + ] + ).dt.days + 1 + + self.df.insert(16, "massimofc", 0) + + self.df["massimofc"] = ( + ( + ( + 0.055 + * ( + self.df["Ore totali rendicontate per il 2020"] + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + self.df["Ore totali rendicontate per il 2020"] + ) + / self.df["GiorniAssistenzaAnnoRiferimento"] + ) * self.df["fc"] + + self.df["massimofc"] = self.df["massimofc"].astype(int) + + if not self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1b & cond1d & NO_ZERO) + ].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + + dftemp = self.df[ + (cond1 & cond1b & cond1c & NO_ZERO) + | (cond1 & cond1b & cond1d & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_bambini_con_valore_massimo_FC_calcolato.xlsx" + ) + self.make_grid(dftemp,"errMassimoFCx",) + # non settiamo Ore totali rendicontate per il flag bool perché non ci serve + + # x = self.dwnld( + # self.df[ + # (cond1 & cond1b & cond1c & NO_ZERO) + # | (cond1 & cond1b & cond1d & NO_ZERO) + # ].sort_values(by=["Cognome e nome bambino"]), + # "Scaricare tabella con bambini con valore massimo FC calcolato", + # "errMassimoFC", + # ) + + def errNomeComuneTagesmutter(self): + # pass + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.write(e) + + condizione1 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Gemeinde"]) + condizione2 = self.df[ + "Comune di residenza assistente domiciliare all'infanzia" + ].isin(dfGemeinden["Comune"]) + condizione = condizione1 | condizione2 + + if not self.df[~condizione].empty: + expndr = st.expander( + f"Trovati {len(self.df[~condizione])} casi con un nome comune Tagesmutter non corrispondente alla lista ufficiale" + ) + + with expndr: + st.info( + "Elenco delle occorrenze con comune Tagesmutter non corrispondente" + ) + dftemp = self.df[~condizione] + if interface.CONVERTIDATESTRINGHE: + dftemp = self.converti_date_in_stringhe(dftemp) + + self.download_excel_file( + dftemp, "errori_nomi_comune_tagesmutter.xlsx" + ) + self.make_grid( + dftemp.sort_values(by=["filename"]), + "errNomeComuneTagesmutterx", + ) + # settiamo il flag bool + self.df.loc[(~condizione), "errNomeComuneTagesmutter"] = True + + del dfGemeinden + + +class caricaEtControlla: + def __init__(self, interface, ERRORDICT): + self.filelist = interface.uploaded_files + self.ANNO_RIFERIMENTO = interface.ANNO_RIFERIMENTO + self.checks = interface.checks + self.ERRORDICT = ERRORDICT + interface.STATUS.info( + "Sono stati caricati " + str(len(self.filelist)) + " files" + ) + + def process_data(self): + """ + Method to load, clean, check for errors, remove duplicates, convert datatypes and rename columns + """ + self.pippo1 = "" + self.pippo2 = "" + self.dataframes = [] + contatorefile = 0 + df = pd.DataFrame + with interface.TAB1: + for file in self.filelist: + try: + interface.STATUS2.info("[*] " + file.name + " caricato") + if self.ANNO_RIFERIMENTO == "2020": + df = pd.read_excel(uploaded_file, usecols="A:M") + elif self.ANNO_RIFERIMENTO == "2021": + # i file excel contengono due sheet nascosti (lista comuni) + # quindi dobbiamo caricare solo quello che si chiama o "deu" o "ita" + try: + df = pd.read_excel(file, sheet_name="ita", usecols="A:L") + except: + self.pippo1 = "ita" + pass + try: + df = pd.read_excel(file, sheet_name="deu", usecols="A:L") + except: + self.pippo2 = "deu" + pass + if self.pippo1 == "ita" and self.pippo2 == "deu": + st.error( + f"file {file.name} non ha il foglio con nome o ita o deu e non viene usato" + ) + self.pippo1 = "" + self.pippo2 = "" + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + # st.write(df) + except Exception as e: + st.error( + file.name + + " non è un file Excel o non corrisponde alla aspettative" + ) + st.error(e) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + continue + contatorefile += 1 + df = self.prepare_data(df, file) + + if df is not None: + df = self.compute_hours(df) + df = self.calcola_giorni_esatti(df) + df = self.make_bool_columns(df) + # df = self.check_data(df) + + self.dataframes.append(df) + + try: + # all loaded excel data gets concatenated in a new dataframe + self.data = pd.concat(self.dataframes, ignore_index=True) + except Exception as e: + st.error("Errore durante concatenamento dei dataframe caricati") + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + pass + + interface.STATUS2.info( + f"Vengono usati {contatorefile} file Excel per l'elaborazione" + ) + + def prepare_data(self, df, file): + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + + if self.ANNO_RIFERIMENTO == "2020": + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4].title() + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3].title() + # st.write(gemeinde) + # st.write(traeger) + + elif self.ANNO_RIFERIMENTO == "2021": + df.columns = [ + "Numero \nprogressivo", + "Cognome", + "Nome", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + # "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 1025/2020", + # "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2021", + ] + # uniamo cognome e nome + df.insert(1, "Cognome e nome bambino", df["Cognome"] + " " + df["Nome"]) + df.drop(["Cognome", "Nome"], axis=1, inplace=True) + traeger = traeger[0].title() + gemeinde = df.iloc[4] + gemeinde = gemeinde[ + 0 + ] # .title() - togliamo title() perche' produce troppip warning + # st.write(gemeinde) + # st.write(traeger) + + gemeindeInserito = gemeinde + + # df["Ore totali rendicontate per il 2021"] = df["Ore totali rendicontate per il 2021"].astype("float") + + try: + dfGemeinden = pd.read_excel("GemeindenComuni.xlsx") + except Exception as e: + st.error( + f"Errore durante caricamento file dei comuni'GemeindenComuni.xlsx'; erore: {e}" + ) + if interface.TOLLERANZAZERO: + st.error("Elaborazione interrotta") + st.stop() + + if ( + gemeindeInserito not in dfGemeinden["Gemeinde"].unique() + and gemeindeInserito not in dfGemeinden["Comune"].unique() + ): + st.warning( + f"L'ente '{traeger}' ha inserito un nome comune non ufficiale: '{gemeindeInserito}'. \n\r Il file verra' usato comunque con il comune inserito. \n\rIl nome file e': {file.name}" + ) + if interface.TOLLERANZAZERO or interface.DEBUGWARNINGS: + st.error("Elaborazione terminata") + st.stop() + + del dfGemeinden + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", file.name) + + # sort per ente + # df = df.sort_values(by="filename") + + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # vediamo se i numero sono progressivi o meno, non critico ma vogliamo un alert + duplicates = df["Numero \nprogressivo"].duplicated(keep=False) + #duplicates = duplicates.sort_values() + + if not df[duplicates].empty: + if interface.MOSTRAERRORIINTEGRITA: + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri NON progressivi nel file {file.name}" + ) + df_no_index = ( + df.loc[ + duplicates, ["Numero \nprogressivo", "Cognome e nome bambino"] + ] + .groupby("Numero \nprogressivo", as_index=False) + .first() + ) + df_no_index["Numero \nprogressivo"] = df_no_index[ + "Numero \nprogressivo" + ].astype(int) + st.write(df_no_index.to_html(index=False), unsafe_allow_html=True) + st.write("") + st.write("") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + + # df.replace('', np.nan, inplace = True) + # controlliamo se hanno immesso un numero progressivo ma sono solo righe vuote + # condition = (~df['number'].isna()) & (df['col1'].isna()) + condizione_righe_vuote = ( + ~df["Numero \nprogressivo"].isna() & df["Cognome e nome bambino"].isna() + ) + if not df[condizione_righe_vuote].empty: + conta_righe = condizione_righe_vuote.sum() + st.warning( + f"Attenzione: l'ente '{traeger}' ha inserito numeri progressivi per righe vuote nel file {file.name}\n\r{conta_righe} righe vuote sono state eliminate e l'elaborazione prosegue" + ) + df = df[~condizione_righe_vuote] + if interface.DEBUGGENERAL: + st.write(df) + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(self.ANNO_RIFERIMENTO) + + #try: + # df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + # "Data fine contratto\n(o data fine assistenza se diversa) *" + # ].astype("datetime64[ns]") + #except Exception as e: + # st.error(f"Errore conversione data fine contratto") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data di nascita contiene valori non data; errore: {e}") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data fine contratto contiene valori non data; errore: {e}") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except Exception as e: + st.error(f"{file.name} --> data inizio contratto contiene valori non data; errore: {e}") + if interface.DEBUGWARNINGS or interface.TOLLERANZAZERO: + st.stop() + return None + + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + + return df + + def compute_hours(self, df): + ar = int(self.ANNO_RIFERIMENTO) # convertiamo anno riferimento in *int* + + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + + df["fineNorm"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + + # calcola il numero giorni esatto, considerando periodi sovvrapposti, inclusi, e gap tra i periodi + # df = calcola_giorni_esatti(df) + + # df["GiorniAssistenzaAnnoRiferimento"] = ( + # df["fineNorm"] - df["inizioNorm"] + # ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + # # + return df + + def calcola_giorni_esatti(self, df): + """ + Calculates the exact number of days of assistance for each person in the given DataFrame. + + Args: + - df (pandas.DataFrame): The DataFrame containing the assistance data for each person. + + Returns: + - pandas.DataFrame: The input DataFrame with an additional column containing the exact number of days of assistance for each person. + """ + + df = df.reset_index(drop=True) + df = df.sort_values( + by="Data inizio contratto (o data inizio assistenza se diversa)" + ) # importante sort, altrimento non calcola giusto + # Group the DataFrame by Codice fiscale + for codice_fiscale, group in df.groupby("Codice fiscale"): + if interface.DEBUGGENERAL: + st.info(f"codice fiscale={codice_fiscale}") + + # Initialize variables for the earliest startdate and latest enddate + earliest_startdate = group.iloc[0]["inizioNorm"] + latest_enddate = group.iloc[0]["fineNorm"] + + if interface.DEBUGGENERAL: + st.info(f"earliest startdate={earliest_startdate}") + st.info(f"latest enddate={latest_enddate}") + + # Initialize variable for total effective days + total_effective_days = 0 + # st.info(codice_fiscale) + # Iterate through each row in the group + for index, row in group.iterrows(): + if interface.DEBUGGENERAL: + st.info(f"index={index}") + # If the enddate is earlier than the latest enddate, skip this row + if row["fineNorm"] < latest_enddate: + continue + + # If the startdate is later than the latest enddate, add the effective days between the earliest startdate and latest enddate to the total effective days + elif row["inizioNorm"] > latest_enddate: + total_effective_days += ( + latest_enddate - earliest_startdate + ).days + 1 + earliest_startdate = row["inizioNorm"] + + # Update the latest enddate + latest_enddate = row["fineNorm"] + indx = index + if interface.DEBUGGENERAL: + st.info(f"temp total effective days={total_effective_days}") + st.info(f"temp earliest startdate{earliest_startdate}") + + # Add the effective days between the earliest startdate and latest enddate to the total effective days + total_effective_days += (latest_enddate - earliest_startdate).days + + # Insert the number of days of assistance into the appropriate row of the DataFrame + # We use the last index in the group because it is the only one that we need to update, and the function that sums the values is correct because it will sum the value with zeros + # st.error(index) + if interface.DEBUGGENERAL: + st.info(f"last index={indx}") + if interface.DEBUGGENERAL: + st.info(f"giorni totali={total_effective_days}") + df["GiorniAssistenzaAnnoRiferimento"][indx] = total_effective_days + 1 + # OR IT WORKS ALSO WITH --> + # df.loc[group.index[-1], "GiorniAssistenzaAnnoRiferimento"] = total_effective_days + 1 + + return df + + def get_data(self): + """ + Method to return the processed data + """ + return self.data + + def make_bool_columns(self, df): + for e in self.ERRORDICT[self.ANNO_RIFERIMENTO].keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +if __name__ == "__main__": + valori = valoriEtErrori() + interface = makeInterface(valori) + + if interface.submit: + if len(interface.uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + interface.make_tabs() + processor = caricaEtControlla(interface, valori.ERRORDICT) + processor.process_data() + errori = trovaErrori(processor.get_data(), interface) + interface.STATUS2.write("") + interface.STATUS.write("") + interface.STATUS3.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) diff --git a/pages/anagrafica.xlsx b/pages/anagrafica.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..82ec4c7dada8d003475153c909fb13f35a52530d --- /dev/null +++ b/pages/anagrafica.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f45353f413b1134d82b527890a83beb99f26b053dd5c4436c26cffe04a9b96cd +size 149114 diff --git a/pages/covid4_gemeinden.ipynb b/pages/covid4_gemeinden.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..39b7cf4a86c9abc3fb46c00ce8417f5f61fcce0d --- /dev/null +++ b/pages/covid4_gemeinden.ipynb @@ -0,0 +1,5929 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 165, + "id": "dcc88334", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import datetime as dt\n", + "import copy\n", + "import openpyxl\n", + "from collections import Counter\n" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "id": "5d5da051-7719-4f25-bbb6-2792a9b02178", + "metadata": {}, + "outputs": [], + "source": [ + "fn = \"errori dopo modifica 2021 - Copy.xlsx\"\n", + "#fn = \"Erklärung Gemeinden Jahr 2020 Tramin.xlsx\"" + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "id": "afbfb93b", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_excel(fn, sheet_name = 'ita',engine = 'openpyxl')#, skiprows = 8)\n", + "#df = pd.read_excel(fn,engine = 'openpyxl')#, skiprows = 8)" + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "id": "e2c1e874", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2021Unnamed: 1Unnamed: 2Unnamed: 3Unnamed: 4Unnamed: 5Unnamed: 6Unnamed: 7Unnamed: 8Unnamed: 9Unnamed: 10Unnamed: 11
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1Ente gestore:NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Casa BimboNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Comune di residenza o di stabile dimora dei ba...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4BolzanoNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
.......................................
87NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
88NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
89NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
90NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
91NaNNaNNaNNaNNaNNaNNaNNaNNaN41788.51744.7543533.25
\n", + "

92 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2021 \\\n", + "0 NaN \n", + "1 Ente gestore: \n", + "2 Casa Bimbo \n", + "3 Comune di residenza o di stabile dimora dei ba... \n", + "4 Bolzano \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Unnamed: 1 Unnamed: 2 Unnamed: 3 Unnamed: 4 Unnamed: 5 Unnamed: 6 \\\n", + "0 NaN NaN NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN NaN NaN \n", + ".. ... ... ... ... ... ... \n", + "87 NaN NaN NaN NaN NaN NaN \n", + "88 NaN NaN NaN NaN NaN NaN \n", + "89 NaN NaN NaN NaN NaN NaN \n", + "90 NaN NaN NaN NaN NaN NaN \n", + "91 NaN NaN NaN NaN NaN NaN \n", + "\n", + " Unnamed: 7 Unnamed: 8 Unnamed: 9 Unnamed: 10 Unnamed: 11 \n", + "0 NaN NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN NaN \n", + ".. ... ... ... ... ... \n", + "87 NaN NaN NaN NaN 0 \n", + "88 NaN NaN NaN NaN 0 \n", + "89 NaN NaN NaN NaN 0 \n", + "90 NaN NaN NaN NaN 0 \n", + "91 NaN NaN 41788.5 1744.75 43533.25 \n", + "\n", + "[92 rows x 12 columns]" + ] + }, + "execution_count": 168, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "id": "eead7b3b", + "metadata": {}, + "outputs": [], + "source": [ + " df.columns = [\n", + " \"Numero \\nprogressivo\",\n", + " \"Cognome\",\n", + " \"Nome\",\n", + " \"Data di nascita\",\n", + " \"Codice fiscale\",\n", + " \"Assistente domiciliare all'infanzia\",\n", + " \"Comune di residenza assistente domiciliare all'infanzia\",\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\",\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\",\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\",\n", + " #\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 543_1025/2020\",\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\",\n", + " #\"Ore contrattualizzate non erogate\\nnella fase 2 (finanziamento compensativo)\",\n", + " \"Ore totali rendicontate per il 2021\",\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "id": "6f06a836", + "metadata": {}, + "outputs": [], + "source": [ + "df.insert(1,\"Cognome e nome bambino\", df[\"Cognome\"] + ' ' + df[\"Nome\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 171, + "id": "b44721c6", + "metadata": {}, + "outputs": [], + "source": [ + "df.drop([\"Cognome\",\"Nome\"], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 172, + "id": "3bac24f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1Ente gestore:NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2Casa BimboNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Comune di residenza o di stabile dimora dei ba...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4BolzanoNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
....................................
87NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
88NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
89NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
90NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN0
91NaNNaNNaNNaNNaNNaNNaNNaN41788.51744.7543533.25
\n", + "

92 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino \\\n", + "0 NaN NaN \n", + "1 Ente gestore: NaN \n", + "2 Casa Bimbo NaN \n", + "3 Comune di residenza o di stabile dimora dei ba... NaN \n", + "4 Bolzano NaN \n", + ".. ... ... \n", + "87 NaN NaN \n", + "88 NaN NaN \n", + "89 NaN NaN \n", + "90 NaN NaN \n", + "91 NaN NaN \n", + "\n", + " Data di nascita Codice fiscale Assistente domiciliare all'infanzia \\\n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 NaN NaN NaN \n", + ".. ... ... ... \n", + "87 NaN NaN NaN \n", + "88 NaN NaN NaN \n", + "89 NaN NaN NaN \n", + "90 NaN NaN NaN \n", + "91 NaN NaN NaN \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 NaN \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 41788.5 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 NaN \n", + "88 NaN \n", + "89 NaN \n", + "90 NaN \n", + "91 1744.75 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "0 NaN \n", + "1 NaN \n", + "2 NaN \n", + "3 NaN \n", + "4 NaN \n", + ".. ... \n", + "87 0 \n", + "88 0 \n", + "89 0 \n", + "90 0 \n", + "91 43533.25 \n", + "\n", + "[92 rows x 11 columns]" + ] + }, + "execution_count": 172, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "id": "9403a634", + "metadata": {}, + "outputs": [], + "source": [ + "traeger = df.iloc[2]" + ] + }, + { + "cell_type": "code", + "execution_count": 174, + "id": "f1509980", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Casa Bimbo '" + ] + }, + "execution_count": 174, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "traeger[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 175, + "id": "7e2e0f52", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = df.iloc[4]" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "id": "62c2a66b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numero \\nprogressivo Bolzano\n", + "Cognome e nome bambino NaN\n", + "Data di nascita NaN\n", + "Codice fiscale NaN\n", + "Assistente domiciliare all'infanzia NaN\n", + "Comune di residenza assistente domiciliare all'infanzia NaN\n", + "Data inizio contratto (o data inizio assistenza se diversa) NaN\n", + "Data fine contratto\\n(o data fine assistenza se diversa) * NaN\n", + "Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 NaN\n", + "Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 NaN\n", + "Ore totali rendicontate per il 2021 NaN\n", + "Name: 4, dtype: object" + ] + }, + "execution_count": 176, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "id": "05d1e376", + "metadata": {}, + "outputs": [], + "source": [ + "gemeinde = gemeinde[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "id": "b4e0ba88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 178, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(traeger[4]) == type(\"string\")" + ] + }, + { + "cell_type": "code", + "execution_count": 179, + "id": "e4eca77c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Bolzano'" + ] + }, + "execution_count": 179, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gemeinde" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "id": "34bd1ed8", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop(labels=range(0, 8), axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 181, + "id": "bb940556", + "metadata": {}, + "outputs": [], + "source": [ + "cond = df[\"Numero \\nprogressivo\"] == \"*\"\n", + "df.loc[cond, \"Numero \\nprogressivo\"] = 99\n", + "df.loc[cond, \"Cognome e nome bambino\"] += \" *\"" + ] + }, + { + "cell_type": "code", + "execution_count": 182, + "id": "eae0703b", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 183, + "id": "fe4b64f7", + "metadata": {}, + "outputs": [], + "source": [ + "validi = df[\"Numero \\nprogressivo\"].notna()" + ] + }, + { + "cell_type": "code", + "execution_count": 184, + "id": "92164e93", + "metadata": {}, + "outputs": [], + "source": [ + "df = df[validi]\n", + "ddff = pd.DataFrame()" + ] + }, + { + "cell_type": "code", + "execution_count": 185, + "id": "eee9a6ec", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 185, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 186, + "id": "ed99ae10", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "600803c2", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Numero \\nprogressivoCognome e nome bambinoData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
81.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
6659.0BAH MAMADOU ADAMA2019-03-22 00:00:00BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31 00:00:00836.25132968.25
\n", + "
" + ], + "text/plain": [ + " Numero \\nprogressivo Cognome e nome bambino Data di nascita \\\n", + "8 1.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "66 59.0 BAH MAMADOU ADAMA 2019-03-22 00:00:00 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 00:00:00 \n", + "66 2022-08-31 00:00:00 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132 \n", + "66 132 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "66 968.25 " + ] + }, + "execution_count": 101, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "condizione1 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] >= pd.to_datetime(\"19.10.2020\", format=\"%d.%m.%Y\")\n", + "condizione2 = df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] < pd.to_datetime(\"22.10.2020\", format=\"%d.%m.%Y\")\n", + "df[condizione1 & condizione2]" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "id": "5ccb9a95", + "metadata": {}, + "outputs": [], + "source": [ + "ddff = pd.DataFrame()\n", + "for ind in df.index:\n", + " if df[\"Comune di residenza assistente domiciliare all'infanzia\"][ind].lower() in (\"bolza\"):\n", + " if df[\"Data inizio contratto (o data inizio assistenza se diversa)\"][ind] > pd.to_datetime(\"17.10.2020\", format=\"%d.%m.%Y\") and df[\"Data inizio contratto (o data inizio assistenza se diversa)\"][ind] < pd.to_datetime(\"30.12.2020\", format=\"%d.%m.%Y\"):\n", + " print(\"bingo\")\n", + " if not ddff.empty:\n", + " print(ind)\n", + " ddff = pd.concat([ddff, df.loc[[ind]]])\n", + " else:\n", + " print(\"empty\")\n", + " print(ind)\n", + " ddff = df.loc[[ind]]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "id": "da922451", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "pandas.core.frame.DataFrame" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(ddff)" + ] + }, + { + "cell_type": "code", + "execution_count": 187, + "id": "d158111c", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "df = df.reindex()" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "id": "390496be", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: []" + ] + }, + "execution_count": 105, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ddff.T" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "id": "265efbee", + "metadata": {}, + "outputs": [], + "source": [ + "c = df[\"Comune di residenza assistente domiciliare all'infanzia\"].str.lower().str.contains('bozen|eppan')" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "id": "90008ae8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['Numero \\nprogressivo', 'Cognome e nome bambino', 'Data di nascita',\n", + " 'Codice fiscale', 'Assistente domiciliare all'infanzia',\n", + " 'Comune di residenza assistente domiciliare all'infanzia',\n", + " 'Data inizio contratto (o data inizio assistenza se diversa)',\n", + " 'Data fine contratto\\n(o data fine assistenza se diversa) *',\n", + " 'Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019',\n", + " 'Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020',\n", + " 'Ore totali rendicontate per il 2021'],\n", + " dtype='object')" + ] + }, + "execution_count": 107, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "id": "80ffa47b", + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'DataFrame' object has no attribute 'colums'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [108]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mdf\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolums\u001b[49m()\n", + "File \u001b[0;32m~/.local/lib/python3.9/site-packages/pandas/core/generic.py:5575\u001b[0m, in \u001b[0;36mNDFrame.__getattr__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 5568\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[1;32m 5569\u001b[0m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_internal_names_set\n\u001b[1;32m 5570\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_metadata\n\u001b[1;32m 5571\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_accessors\n\u001b[1;32m 5572\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_info_axis\u001b[38;5;241m.\u001b[39m_can_hold_identifiers_and_holds_name(name)\n\u001b[1;32m 5573\u001b[0m ):\n\u001b[1;32m 5574\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m[name]\n\u001b[0;32m-> 5575\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mobject\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__getattribute__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mname\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'DataFrame' object has no attribute 'colums'" + ] + } + ], + "source": [ + "df.colums()" + ] + }, + { + "cell_type": "code", + "execution_count": 188, + "id": "161dc59a", + "metadata": {}, + "outputs": [], + "source": [ + " condizione = pd.isnull(\n", + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 189, + "id": "9750c61f", + "metadata": {}, + "outputs": [], + "source": [ + " anno_riferimento = 2020\n", + " df.loc[\n", + " condizione, \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ] = \"12-31-\" + str(anno_riferimento)" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "id": "6a9d1191", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 191, + "id": "b72f7c18", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Data di nascita\"] = df[\"Data di nascita\"].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 192, + "id": "099e79dc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"] = df[\n", + " \"Data fine contratto\\n(o data fine assistenza se diversa) *\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 193, + "id": "496b8413", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Data inizio contratto (o data inizio assistenza se diversa)\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ].astype(\"datetime64[ns]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "id": "39bd383d", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"Numero \\nprogressivo\"] = pd.to_numeric(\n", + " df[\"Numero \\nprogressivo\"], errors=\"coerce\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 195, + "id": "b0321529", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.drop([\"Numero \\nprogressivo\"], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 196, + "id": "78f1205a", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(1, \"Comune\", gemeinde)\n", + " df.insert(1, \"Ente\", traeger)" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "id": "0d1a703f", + "metadata": {}, + "outputs": [], + "source": [ + "df = df.fillna(0)" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "id": "309315c9", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"Codice fiscale\"] = df[\"Codice fiscale\"].str.upper()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "99cd2373", + "metadata": {}, + "outputs": [], + "source": [ + "ar = 2020" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "13cff4e9", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"inizioNorm\"] = df[\n", + " \"Data inizio contratto (o data inizio assistenza se diversa)\"\n", + " ]" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "d12529dc", + "metadata": {}, + "outputs": [], + "source": [ + "df[\"fineNorm\"] = df[\"Data fine contratto\\n(o data fine assistenza se diversa) *\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "16d50f89", + "metadata": {}, + "outputs": [], + "source": [ + "iniz = df[\"inizioNorm\"].dt.year < ar" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "82b5fff9", + "metadata": {}, + "outputs": [], + "source": [ + " df.loc[iniz, \"inizioNorm\"] = \"01-01-\" + str(\n", + " ar\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "d006d5a2", + "metadata": {}, + "outputs": [], + "source": [ + "fin = df[\"fineNorm\"].dt.year > ar" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "1ac5f37f", + "metadata": {}, + "outputs": [], + "source": [ + "df.loc[fin, \"fineNorm\"] = \"12-31-\" + str(ar)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "998073a9", + "metadata": {}, + "outputs": [], + "source": [ + " df.insert(\n", + " 9, \"GiorniAssistenzaAnnoRiferimento\", 0\n", + " ) " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "24e02bcc", + "metadata": {}, + "outputs": [], + "source": [ + " df[\"GiorniAssistenzaAnnoRiferimento\"] = (\n", + " df[\"fineNorm\"] - df[\"inizioNorm\"]\n", + " ).dt.days + 1" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "af6a6cf6", + "metadata": {}, + "outputs": [], + "source": [ + " condizioneerrore = ((1920 * (df[\"GiorniAssistenzaAnnoRiferimento\"])) / 366) < df[\n", + " \"Ore totali rendicontate per il 2020\"\n", + " ]\n", + " \n", + " condizioneerrore2 = ((1920 * (df.groupby(\"Codice fiscale\")[\"GiorniAssistenzaAnnoRiferimento\"].transform(\"sum\")) / 366)) < df.groupby(\"Codice fiscale\")[\"Ore totali rendicontate per il 2020\"].transform(\"sum\")" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "08e4a7e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "TMGMRM19B41A952N\n", + "VNCDLN19B19A952G\n", + "ZLGSML18E08F132P\n", + "ZLGSML18E08F132P\n" + ] + } + ], + "source": [ + "for i in df[condizioneerrore][\"Codice fiscale\"]:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "id": "29ed03dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26935.2521.25956.50
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01605.500.00605.50
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0884.000.0084.00
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03690.0030.75720.75
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02965.5022.50988.00
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17462.500.00462.50
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-311314.500.001314.50
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01274.5039.00313.50
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06592.0022.00614.00
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-021269.7531.501301.25
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30372.0020.00392.00
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171010.5022.001032.50
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25652.0030.00682.00
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29940.500.00940.50
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-151338.75110.001448.75
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28575.500.00575.50
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31812.2576.00888.25
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02428.0020.00448.00
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02474.5078.00552.50
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24979.00110.001089.00
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-31263.5058.50322.00
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31806.500.00806.50
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-311016.0060.001076.00
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02616.000.00616.00
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-1795.000.0095.00
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31488.0020.00508.00
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-30140.000.00140.00
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31587.7523.50611.25
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04573.0020.00593.00
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-281211.750.001211.75
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30476.0020.00496.00
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27469.5023.50493.00
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02200.250.00200.25
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31973.0095.001068.00
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01493.5078.00571.50
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24562.5022.50585.00
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16427.250.00427.25
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06950.7532.00982.75
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-311405.0035.001440.00
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08632.500.00632.50
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-01248.250.00248.25
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-30213.000.00213.00
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31543.750.00543.75
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31706.000.00706.00
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31496.0020.00516.00
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-17108.500.00108.50
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-041353.2532.501385.75
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-311643.50132.001775.50
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03695.0063.00758.00
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10879.5021.25900.75
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-02276.000.00276.00
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-311328.5025.001353.50
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30543.000.00543.00
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01401.500.00401.50
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-311734.000.001734.00
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02629.500.00629.50
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-261152.5066.001218.50
66BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "66 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "66 2022-08-31 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "9 956.50 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 720.75 \n", + "13 988.00 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 313.50 \n", + "17 614.00 \n", + "18 1301.25 \n", + "19 392.00 \n", + "20 1032.50 \n", + "21 682.00 \n", + "22 940.50 \n", + "23 1448.75 \n", + "24 575.50 \n", + "25 888.25 \n", + "26 448.00 \n", + "27 552.50 \n", + "28 1089.00 \n", + "29 322.00 \n", + "30 806.50 \n", + "31 1076.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 508.00 \n", + "35 140.00 \n", + "36 611.25 \n", + "37 593.00 \n", + "38 1211.75 \n", + "39 496.00 \n", + "40 493.00 \n", + "41 200.25 \n", + "42 1068.00 \n", + "43 571.50 \n", + "44 585.00 \n", + "45 427.25 \n", + "46 982.75 \n", + "47 1440.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 516.00 \n", + "54 108.50 \n", + "55 1385.75 \n", + "56 1775.50 \n", + "57 758.00 \n", + "58 900.75 \n", + "59 276.00 \n", + "60 1353.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1218.50 \n", + "66 968.25 " + ] + }, + "execution_count": 125, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "id": "4acf4374", + "metadata": {}, + "outputs": [], + "source": [ + " df2 = df.groupby(\"Comune\", as_index=False)[\n", + " \"Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019\"\n", + " ].apply(lambda x: x[x > 0].count())" + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "id": "22cbf3b4", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26935.2521.25956.50
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01605.500.00605.50
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0884.000.0084.00
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03690.0030.75720.75
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02965.5022.50988.00
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17462.500.00462.50
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-311314.500.001314.50
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01274.5039.00313.50
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06592.0022.00614.00
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-021269.7531.501301.25
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30372.0020.00392.00
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171010.5022.001032.50
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25652.0030.00682.00
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29940.500.00940.50
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-151338.75110.001448.75
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28575.500.00575.50
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31812.2576.00888.25
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02428.0020.00448.00
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02474.5078.00552.50
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24979.00110.001089.00
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-31263.5058.50322.00
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31806.500.00806.50
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-311016.0060.001076.00
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02616.000.00616.00
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-1795.000.0095.00
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31488.0020.00508.00
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-30140.000.00140.00
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31587.7523.50611.25
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04573.0020.00593.00
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-281211.750.001211.75
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30476.0020.00496.00
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27469.5023.50493.00
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02200.250.00200.25
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31973.0095.001068.00
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01493.5078.00571.50
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24562.5022.50585.00
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16427.250.00427.25
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06950.7532.00982.75
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-311405.0035.001440.00
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08632.500.00632.50
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-01248.250.00248.25
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-30213.000.00213.00
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31543.750.00543.75
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31706.000.00706.00
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31496.0020.00516.00
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-17108.500.00108.50
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-041353.2532.501385.75
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-311643.50132.001775.50
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03695.0063.00758.00
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10879.5021.25900.75
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-02276.000.00276.00
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-311328.5025.001353.50
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30543.000.00543.00
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01401.500.00401.50
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-311734.000.001734.00
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02629.500.00629.50
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-261152.5066.001218.50
66BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "66 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "66 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "66 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "66 2020-10-19 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "66 2022-08-31 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "66 836.25 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "66 132.00 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "9 956.50 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 720.75 \n", + "13 988.00 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 313.50 \n", + "17 614.00 \n", + "18 1301.25 \n", + "19 392.00 \n", + "20 1032.50 \n", + "21 682.00 \n", + "22 940.50 \n", + "23 1448.75 \n", + "24 575.50 \n", + "25 888.25 \n", + "26 448.00 \n", + "27 552.50 \n", + "28 1089.00 \n", + "29 322.00 \n", + "30 806.50 \n", + "31 1076.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 508.00 \n", + "35 140.00 \n", + "36 611.25 \n", + "37 593.00 \n", + "38 1211.75 \n", + "39 496.00 \n", + "40 493.00 \n", + "41 200.25 \n", + "42 1068.00 \n", + "43 571.50 \n", + "44 585.00 \n", + "45 427.25 \n", + "46 982.75 \n", + "47 1440.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 516.00 \n", + "54 108.50 \n", + "55 1385.75 \n", + "56 1775.50 \n", + "57 758.00 \n", + "58 900.75 \n", + "59 276.00 \n", + "60 1353.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1218.50 \n", + "66 968.25 " + ] + }, + "execution_count": 204, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "id": "71b02919", + "metadata": {}, + "outputs": [], + "source": [ + "#c = df[\"Codice fiscale\"].unique\n", + "dfx = df.drop_duplicates(subset = [\"Codice fiscale\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "id": "ea1a0a2d", + "metadata": {}, + "outputs": [], + "source": [ + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0" + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "id": "0db71170", + "metadata": {}, + "outputs": [], + "source": [ + " df2bis = dfx[c].groupby(\"Comune\", as_index=False)[\n", + " \"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"\n", + " ].apply(lambda x: x[x > 0].sum())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "634575da", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneOre contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020
0Bolzano1612.75
\n", + "
" + ], + "text/plain": [ + " Comune \\\n", + "0 Bolzano \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \n", + "0 1612.75 " + ] + }, + "execution_count": 223, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2bis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "129075cb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 207, + "id": "8e1896c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "34" + ] + }, + "execution_count": 207, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#dfx = df.groupby(\"Codice fiscale\", as_index = False)\n", + "c = dfx[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"] > 0\n", + "len(dfx[c])" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "id": "2d98620d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Cognome e nome bambinoEnteComuneData di nascitaCodice fiscaleAssistente domiciliare all'infanziaComune di residenza assistente domiciliare all'infanziaData inizio contratto (o data inizio assistenza se diversa)Data fine contratto\\n(o data fine assistenza se diversa) *Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020Ore totali rendicontate per il 2021
8BAH MAMADOU ADAMA0Bolzano2019-03-22BHMDMA19C62A952YLOVATO DEBORAHBOLZANO2020-10-192022-08-31836.25132.00968.25
9TUCCIO GABRIEL0Bolzano2019-03-23TCCGRL19C23A952WMARTINELLO SILVIABOLZANO2020-06-082022-08-26935.2521.25956.50
10GAMBINO AMBRA0Bolzano2018-05-05GMBMBR18E45A952RMATTEOTTI GIACOMOBOLZANO2019-09-022021-07-01605.500.00605.50
11BISULTANOV MANSUR0Bolzano2019-08-20BSLMSR19M20A952UIVANOVIC JASNAMERANO2021-02-192021-06-0884.000.0084.00
12DELVAI MATTEO0Bolzano2018-04-18DLVMTT18D18A952JMATTEOTTI GIACOMOBOLZANO2019-08-192021-07-03690.0030.75720.75
13TOSI SOFIA0Bolzano2019-06-02TSOSFO19H42A952YMARTINELLO SILVIABOLZANO2020-06-082022-09-02965.5022.50988.00
14BRAHAJ SJORDI0Bolzano2020-08-16BRHSRD20M56A952HKOTI ALMABOLZANO2021-09-132022-06-17462.500.00462.50
15BUCCELLA LORENZO0Bolzano2019-10-22BCCLNZ19R22F132WMATTEOTTI GIACOMOBOLZANO2020-06-292022-08-311314.500.001314.50
16FIALCOVSCHI ALEXANDRU0Bolzano2020-08-12FLCLND20M12A952TLOVATO DEBORAHBOLZANO2021-09-062023-09-01274.5039.00313.50
17CHIHI LISA0Bolzano2018-02-20CHHLSI18B60A952CCARUSO MARIASCENA2021-02-252021-08-06592.0022.00614.00
18LANARI ARIANNA0Bolzano2018-11-20LNRRNN18S60A952DMATTEOTTI GIACOMOBOLZANO2020-08-172022-09-021269.7531.501301.25
19PATRICELLI GIULIA0Bolzano2020-03-08PTRGLI20C48A952IIVANOVIC JASNASCENA2021-03-022021-07-30372.0020.00392.00
20SMITH LIAM0Bolzano2019-03-22SMTLMI19C22A952XKOTI ALMABOLZANO2020-08-252021-07-171010.5022.001032.50
21CORNESCU DANIELE0Bolzano2018-11-19CRNDNL18S19A952TKOTI ALMABOLZANO2020-09-282021-06-25652.0030.00682.00
22SCARATTI FRANCESCA0Bolzano2019-08-10SCRFNC19M50A952JMOSSA DANIELABOLZANO2021-02-242022-07-29940.500.00940.50
23BARDINI MARCO0Bolzano2019-11-28BRDMRC19S28A952PPRAZARU OLENABOLZANO2020-08-172022-08-151338.75110.001448.75
24DALL'ARMELLINA PIETRO0Bolzano2019-05-16DLLPTR19E07A952EMATTEOTTI GIACOMOBOLZANO2019-09-232021-05-28575.500.00575.50
25DE LUCIA MARTINA0Bolzano2018-02-27DLCMTN18B67A952ULOVATO DEBORAHBOLZANO2020-09-282021-08-31812.2576.00888.25
26DE PALMA ALESSANDRO0Bolzano2018-12-12DPLLSN18T12B455OIVANOVIC JASNABOLZANO2020-01-292021-07-02428.0020.00448.00
27MOHAMMAD SALEEH BERITAN0Bolzano2019-01-04MHMBTN19A44A952VLOVATO DEBORAHBOLZANO2021-09-202022-09-02474.5078.00552.50
28PEREZZANI NOELLE0Bolzano2019-10-24PRZNLL19R64A952EPRAZARU OLENABOLZANO2020-08-262021-08-24979.00110.001089.00
29DI FEBBRAIO GIUSEPPE0Bolzano2020-02-06DFBGPP20B06A952JLOVATO DEBORAHBOLZANO2021-10-042023-08-31263.5058.50322.00
30DI PIERRO ALICE0Bolzano2018-08-24DPRLCA18M64A952OMOSSA DANIELABOLZANO2019-02-182021-08-31806.500.00806.50
31DONOLA MATILDE0Bolzano2019-02-15DNLMLD19B55A952XCAROTTA SILVIABOLZANO2020-09-282022-08-311016.0060.001076.00
32KHOUIA HIBA0Bolzano2019-08-08KHOHBI19M48A952MMOSSA DANIELARIFIANO2021-02-042022-09-02616.000.00616.00
33KANOUNE MARYEM ELBATOUL0Bolzano2019-03-29KNNMYM19C69A952ZCARUSO MARIABOLZANO2021-12-062022-06-1795.000.0095.00
34EL HAMDAOUI NIZAR0Bolzano2020-04-06LHMNZR20D60A952KIVANOVIC JASNABOLZANO2021-01-042021-07-31488.0020.00508.00
35AYALA GALLEGOS JAYDEN0Bolzano2020-11-22YLGJDN20S22A952ECARUSO MARIABOLZANO2021-11-222024-08-30140.000.00140.00
36GASHI AMRA0Bolzano2018-05-04GSHMRA18E44A952BKOTI ALMA/MOSSA DANIELABOLZANO2019-09-022021-07-31587.7523.50611.25
37SICOLO FRANCESCO0Bolzano2019-12-06SCLFNC19T06A952KCARUSO MARIABOLZANO2020-08-312021-08-04573.0020.00593.00
38DI MARCO ANITA0Bolzano2020-03-11DMRNTA20C51A952WKOTI ALMABOLZANO2020-08-312023-07-281211.750.001211.75
39HYSENAJ ESLI0Bolzano2018-10-24HYSSLE18R24A952HIVANOVIC JASNABOLZANO2020-09-072021-07-30476.0020.00496.00
40BILAL SHAMIR0Bolzano2018-05-11BLLSMR18E11A952NMILITARU ROXANA/CARUSO MARIABOLZANO2020-08-032021-08-27469.5023.50493.00
41LLESHI DANIEL0Bolzano2021-05-23LLSDNL21E23A952MMOSSA DANIELASCENA2021-03-012022-09-02200.250.00200.25
42LORENZINI MARINA0Bolzano2018-11-05LRNMRN18S45F132ULOVATO DEBORAHBOLZANO2020-01-132021-08-31973.0095.001068.00
43LOTIERZO NICOLO'0Bolzano2019-12-07LTRNCL19T07A952BLOVATO DEBORAHBOLZANO2021-08-302023-09-01493.5078.00571.50
44MIRA TEO0Bolzano2019-05-20MRITEO19E20F132AMOSSA DANIELABOLZANO2020-08-242021-08-24562.5022.50585.00
45VENTURINI AURORA0Bolzano2020-07-20VNTRRA20L60A952FKOTI ALMABOLZANO2021-09-062022-06-16427.250.00427.25
46MION GINEVRA0Bolzano2018-08-27MNIGVR18M67A952HMARTINELLO SILVIABOLZANO2021-02-102021-09-06950.7532.00982.75
47NEZA REAN0Bolzano2019-04-14NZERNE19D14F257XKOTI ALMABOLZANO2020-10-132022-07-311405.0035.001440.00
48PEDINI LILIANA0Bolzano2019-03-26PDNLLN19C66A952QMOSSA DANIELABOLZANO2019-09-022021-10-08632.500.00632.50
49PEREZ PONCE ELLIE0Bolzano2020-08-28PRZLLE20M68A952LPRAZARU OLENABOLZANO2021-10-182023-09-01248.250.00248.25
50CIRILLO JACOPO0Bolzano2021-05-26CRLJCP21E26F132NMARTINELLO SILVIABOLZANO2021-10-112022-09-30213.000.00213.00
51BAR NICHOLAS0Bolzano2020-07-15BRANHL20L15A952JMOSSA DANIELABOLZANO2021-08-302023-08-31543.750.00543.75
52CUEL MATAN0Bolzano2020-09-01CLUMTN20P01A952GMATTEOTTI GIACOMOBOLZANO2021-05-252023-08-31706.000.00706.00
53POPESCU MATEI0Bolzano2019-02-21PPSMTA19B21A952UIVANOVIC JASNABOLZANO2020-06-012021-07-31496.0020.00516.00
54PASCARELLA DOMENICO0Bolzano2019-03-28PSCDNC19C28A952NCAROTTA SILVIABOLZANO2021-11-082022-06-17108.500.00108.50
55CAMPARETTO ROCCA EDOARDO0Bolzano2020-02-19CMPDRD20B19A952OMARTINELLO SILVIABOLZANO2020-08-312022-01-041353.2532.501385.75
56FIORE LEONARDO0Bolzano2019-12-31FRILRD19T31F132GPRAZARU OLENABOLZANO2020-10-052022-12-311643.50132.001775.50
57DE COL BEATRICE0Bolzano2018-09-07DCLBRC18P47A952JCAROTTA SILVIABOLZANO2020-03-022021-09-03695.0063.00758.00
58SOTA PAOLA0Bolzano2018-08-29STOPLA18L69A952BMARTINELLO SILVIABOLZANO2019-09-232021-09-10879.5021.25900.75
59TATARI SAUL0Bolzano2019-12-30TTRSLA19T30A952RMATTEOTTI GIACOMOBOLZANO2021-10-182022-09-02276.000.00276.00
60TRINCO ANITA0Bolzano2020-05-30TRNNTA20E70A952BCARUSO MARIABOLZANO2020-12-282023-08-311328.5025.001353.50
61VALLAZZA ISABEL0Bolzano2020-06-23VLLSBL20H63A952QCARUSO MARIABOLZANO2021-06-282022-06-30543.000.00543.00
62MANGIALAIO LEON0Bolzano2020-10-08MNGLNE20R08B220SMATTEOTTI GIACOMOBOLZANO2021-09-202023-09-01401.500.00401.50
63WEGLEITER ENEAS0Bolzano2018-10-22WGLNSE18R22B160OMOSSA DANIELABOLZANO2020-07-132022-08-311734.000.001734.00
64SAID ZAYD0Bolzano2019-05-26SDAZYD19E26G224VCARUSO MARIABOLZANO2021-08-302022-09-02629.500.00629.50
65RINDONE FILIPPO TOMMASO0Bolzano2019-10-31RNDFPP19R31A952YCAROTTA SILVIABOLZANO2020-08-312022-08-261152.5066.001218.50
\n", + "
" + ], + "text/plain": [ + " Cognome e nome bambino Ente Comune Data di nascita \\\n", + "8 BAH MAMADOU ADAMA 0 Bolzano 2019-03-22 \n", + "9 TUCCIO GABRIEL 0 Bolzano 2019-03-23 \n", + "10 GAMBINO AMBRA 0 Bolzano 2018-05-05 \n", + "11 BISULTANOV MANSUR 0 Bolzano 2019-08-20 \n", + "12 DELVAI MATTEO 0 Bolzano 2018-04-18 \n", + "13 TOSI SOFIA 0 Bolzano 2019-06-02 \n", + "14 BRAHAJ SJORDI 0 Bolzano 2020-08-16 \n", + "15 BUCCELLA LORENZO 0 Bolzano 2019-10-22 \n", + "16 FIALCOVSCHI ALEXANDRU 0 Bolzano 2020-08-12 \n", + "17 CHIHI LISA 0 Bolzano 2018-02-20 \n", + "18 LANARI ARIANNA 0 Bolzano 2018-11-20 \n", + "19 PATRICELLI GIULIA 0 Bolzano 2020-03-08 \n", + "20 SMITH LIAM 0 Bolzano 2019-03-22 \n", + "21 CORNESCU DANIELE 0 Bolzano 2018-11-19 \n", + "22 SCARATTI FRANCESCA 0 Bolzano 2019-08-10 \n", + "23 BARDINI MARCO 0 Bolzano 2019-11-28 \n", + "24 DALL'ARMELLINA PIETRO 0 Bolzano 2019-05-16 \n", + "25 DE LUCIA MARTINA 0 Bolzano 2018-02-27 \n", + "26 DE PALMA ALESSANDRO 0 Bolzano 2018-12-12 \n", + "27 MOHAMMAD SALEEH BERITAN 0 Bolzano 2019-01-04 \n", + "28 PEREZZANI NOELLE 0 Bolzano 2019-10-24 \n", + "29 DI FEBBRAIO GIUSEPPE 0 Bolzano 2020-02-06 \n", + "30 DI PIERRO ALICE 0 Bolzano 2018-08-24 \n", + "31 DONOLA MATILDE 0 Bolzano 2019-02-15 \n", + "32 KHOUIA HIBA 0 Bolzano 2019-08-08 \n", + "33 KANOUNE MARYEM ELBATOUL 0 Bolzano 2019-03-29 \n", + "34 EL HAMDAOUI NIZAR 0 Bolzano 2020-04-06 \n", + "35 AYALA GALLEGOS JAYDEN 0 Bolzano 2020-11-22 \n", + "36 GASHI AMRA 0 Bolzano 2018-05-04 \n", + "37 SICOLO FRANCESCO 0 Bolzano 2019-12-06 \n", + "38 DI MARCO ANITA 0 Bolzano 2020-03-11 \n", + "39 HYSENAJ ESLI 0 Bolzano 2018-10-24 \n", + "40 BILAL SHAMIR 0 Bolzano 2018-05-11 \n", + "41 LLESHI DANIEL 0 Bolzano 2021-05-23 \n", + "42 LORENZINI MARINA 0 Bolzano 2018-11-05 \n", + "43 LOTIERZO NICOLO' 0 Bolzano 2019-12-07 \n", + "44 MIRA TEO 0 Bolzano 2019-05-20 \n", + "45 VENTURINI AURORA 0 Bolzano 2020-07-20 \n", + "46 MION GINEVRA 0 Bolzano 2018-08-27 \n", + "47 NEZA REAN 0 Bolzano 2019-04-14 \n", + "48 PEDINI LILIANA 0 Bolzano 2019-03-26 \n", + "49 PEREZ PONCE ELLIE 0 Bolzano 2020-08-28 \n", + "50 CIRILLO JACOPO 0 Bolzano 2021-05-26 \n", + "51 BAR NICHOLAS 0 Bolzano 2020-07-15 \n", + "52 CUEL MATAN 0 Bolzano 2020-09-01 \n", + "53 POPESCU MATEI 0 Bolzano 2019-02-21 \n", + "54 PASCARELLA DOMENICO 0 Bolzano 2019-03-28 \n", + "55 CAMPARETTO ROCCA EDOARDO 0 Bolzano 2020-02-19 \n", + "56 FIORE LEONARDO 0 Bolzano 2019-12-31 \n", + "57 DE COL BEATRICE 0 Bolzano 2018-09-07 \n", + "58 SOTA PAOLA 0 Bolzano 2018-08-29 \n", + "59 TATARI SAUL 0 Bolzano 2019-12-30 \n", + "60 TRINCO ANITA 0 Bolzano 2020-05-30 \n", + "61 VALLAZZA ISABEL 0 Bolzano 2020-06-23 \n", + "62 MANGIALAIO LEON 0 Bolzano 2020-10-08 \n", + "63 WEGLEITER ENEAS 0 Bolzano 2018-10-22 \n", + "64 SAID ZAYD 0 Bolzano 2019-05-26 \n", + "65 RINDONE FILIPPO TOMMASO 0 Bolzano 2019-10-31 \n", + "\n", + " Codice fiscale Assistente domiciliare all'infanzia \\\n", + "8 BHMDMA19C62A952Y LOVATO DEBORAH \n", + "9 TCCGRL19C23A952W MARTINELLO SILVIA \n", + "10 GMBMBR18E45A952R MATTEOTTI GIACOMO \n", + "11 BSLMSR19M20A952U IVANOVIC JASNA \n", + "12 DLVMTT18D18A952J MATTEOTTI GIACOMO \n", + "13 TSOSFO19H42A952Y MARTINELLO SILVIA \n", + "14 BRHSRD20M56A952H KOTI ALMA \n", + "15 BCCLNZ19R22F132W MATTEOTTI GIACOMO \n", + "16 FLCLND20M12A952T LOVATO DEBORAH \n", + "17 CHHLSI18B60A952C CARUSO MARIA \n", + "18 LNRRNN18S60A952D MATTEOTTI GIACOMO \n", + "19 PTRGLI20C48A952I IVANOVIC JASNA \n", + "20 SMTLMI19C22A952X KOTI ALMA \n", + "21 CRNDNL18S19A952T KOTI ALMA \n", + "22 SCRFNC19M50A952J MOSSA DANIELA \n", + "23 BRDMRC19S28A952P PRAZARU OLENA \n", + "24 DLLPTR19E07A952E MATTEOTTI GIACOMO \n", + "25 DLCMTN18B67A952U LOVATO DEBORAH \n", + "26 DPLLSN18T12B455O IVANOVIC JASNA \n", + "27 MHMBTN19A44A952V LOVATO DEBORAH \n", + "28 PRZNLL19R64A952E PRAZARU OLENA \n", + "29 DFBGPP20B06A952J LOVATO DEBORAH \n", + "30 DPRLCA18M64A952O MOSSA DANIELA \n", + "31 DNLMLD19B55A952X CAROTTA SILVIA \n", + "32 KHOHBI19M48A952M MOSSA DANIELA \n", + "33 KNNMYM19C69A952Z CARUSO MARIA \n", + "34 LHMNZR20D60A952K IVANOVIC JASNA \n", + "35 YLGJDN20S22A952E CARUSO MARIA \n", + "36 GSHMRA18E44A952B KOTI ALMA/MOSSA DANIELA \n", + "37 SCLFNC19T06A952K CARUSO MARIA \n", + "38 DMRNTA20C51A952W KOTI ALMA \n", + "39 HYSSLE18R24A952H IVANOVIC JASNA \n", + "40 BLLSMR18E11A952N MILITARU ROXANA/CARUSO MARIA \n", + "41 LLSDNL21E23A952M MOSSA DANIELA \n", + "42 LRNMRN18S45F132U LOVATO DEBORAH \n", + "43 LTRNCL19T07A952B LOVATO DEBORAH \n", + "44 MRITEO19E20F132A MOSSA DANIELA \n", + "45 VNTRRA20L60A952F KOTI ALMA \n", + "46 MNIGVR18M67A952H MARTINELLO SILVIA \n", + "47 NZERNE19D14F257X KOTI ALMA \n", + "48 PDNLLN19C66A952Q MOSSA DANIELA \n", + "49 PRZLLE20M68A952L PRAZARU OLENA \n", + "50 CRLJCP21E26F132N MARTINELLO SILVIA \n", + "51 BRANHL20L15A952J MOSSA DANIELA \n", + "52 CLUMTN20P01A952G MATTEOTTI GIACOMO \n", + "53 PPSMTA19B21A952U IVANOVIC JASNA \n", + "54 PSCDNC19C28A952N CAROTTA SILVIA \n", + "55 CMPDRD20B19A952O MARTINELLO SILVIA \n", + "56 FRILRD19T31F132G PRAZARU OLENA \n", + "57 DCLBRC18P47A952J CAROTTA SILVIA \n", + "58 STOPLA18L69A952B MARTINELLO SILVIA \n", + "59 TTRSLA19T30A952R MATTEOTTI GIACOMO \n", + "60 TRNNTA20E70A952B CARUSO MARIA \n", + "61 VLLSBL20H63A952Q CARUSO MARIA \n", + "62 MNGLNE20R08B220S MATTEOTTI GIACOMO \n", + "63 WGLNSE18R22B160O MOSSA DANIELA \n", + "64 SDAZYD19E26G224V CARUSO MARIA \n", + "65 RNDFPP19R31A952Y CAROTTA SILVIA \n", + "\n", + " Comune di residenza assistente domiciliare all'infanzia \\\n", + "8 BOLZANO \n", + "9 BOLZANO \n", + "10 BOLZANO \n", + "11 MERANO \n", + "12 BOLZANO \n", + "13 BOLZANO \n", + "14 BOLZANO \n", + "15 BOLZANO \n", + "16 BOLZANO \n", + "17 SCENA \n", + "18 BOLZANO \n", + "19 SCENA \n", + "20 BOLZANO \n", + "21 BOLZANO \n", + "22 BOLZANO \n", + "23 BOLZANO \n", + "24 BOLZANO \n", + "25 BOLZANO \n", + "26 BOLZANO \n", + "27 BOLZANO \n", + "28 BOLZANO \n", + "29 BOLZANO \n", + "30 BOLZANO \n", + "31 BOLZANO \n", + "32 RIFIANO \n", + "33 BOLZANO \n", + "34 BOLZANO \n", + "35 BOLZANO \n", + "36 BOLZANO \n", + "37 BOLZANO \n", + "38 BOLZANO \n", + "39 BOLZANO \n", + "40 BOLZANO \n", + "41 SCENA \n", + "42 BOLZANO \n", + "43 BOLZANO \n", + "44 BOLZANO \n", + "45 BOLZANO \n", + "46 BOLZANO \n", + "47 BOLZANO \n", + "48 BOLZANO \n", + "49 BOLZANO \n", + "50 BOLZANO \n", + "51 BOLZANO \n", + "52 BOLZANO \n", + "53 BOLZANO \n", + "54 BOLZANO \n", + "55 BOLZANO \n", + "56 BOLZANO \n", + "57 BOLZANO \n", + "58 BOLZANO \n", + "59 BOLZANO \n", + "60 BOLZANO \n", + "61 BOLZANO \n", + "62 BOLZANO \n", + "63 BOLZANO \n", + "64 BOLZANO \n", + "65 BOLZANO \n", + "\n", + " Data inizio contratto (o data inizio assistenza se diversa) \\\n", + "8 2020-10-19 \n", + "9 2020-06-08 \n", + "10 2019-09-02 \n", + "11 2021-02-19 \n", + "12 2019-08-19 \n", + "13 2020-06-08 \n", + "14 2021-09-13 \n", + "15 2020-06-29 \n", + "16 2021-09-06 \n", + "17 2021-02-25 \n", + "18 2020-08-17 \n", + "19 2021-03-02 \n", + "20 2020-08-25 \n", + "21 2020-09-28 \n", + "22 2021-02-24 \n", + "23 2020-08-17 \n", + "24 2019-09-23 \n", + "25 2020-09-28 \n", + "26 2020-01-29 \n", + "27 2021-09-20 \n", + "28 2020-08-26 \n", + "29 2021-10-04 \n", + "30 2019-02-18 \n", + "31 2020-09-28 \n", + "32 2021-02-04 \n", + "33 2021-12-06 \n", + "34 2021-01-04 \n", + "35 2021-11-22 \n", + "36 2019-09-02 \n", + "37 2020-08-31 \n", + "38 2020-08-31 \n", + "39 2020-09-07 \n", + "40 2020-08-03 \n", + "41 2021-03-01 \n", + "42 2020-01-13 \n", + "43 2021-08-30 \n", + "44 2020-08-24 \n", + "45 2021-09-06 \n", + "46 2021-02-10 \n", + "47 2020-10-13 \n", + "48 2019-09-02 \n", + "49 2021-10-18 \n", + "50 2021-10-11 \n", + "51 2021-08-30 \n", + "52 2021-05-25 \n", + "53 2020-06-01 \n", + "54 2021-11-08 \n", + "55 2020-08-31 \n", + "56 2020-10-05 \n", + "57 2020-03-02 \n", + "58 2019-09-23 \n", + "59 2021-10-18 \n", + "60 2020-12-28 \n", + "61 2021-06-28 \n", + "62 2021-09-20 \n", + "63 2020-07-13 \n", + "64 2021-08-30 \n", + "65 2020-08-31 \n", + "\n", + " Data fine contratto\\n(o data fine assistenza se diversa) * \\\n", + "8 2022-08-31 \n", + "9 2022-08-26 \n", + "10 2021-07-01 \n", + "11 2021-06-08 \n", + "12 2021-07-03 \n", + "13 2022-09-02 \n", + "14 2022-06-17 \n", + "15 2022-08-31 \n", + "16 2023-09-01 \n", + "17 2021-08-06 \n", + "18 2022-09-02 \n", + "19 2021-07-30 \n", + "20 2021-07-17 \n", + "21 2021-06-25 \n", + "22 2022-07-29 \n", + "23 2022-08-15 \n", + "24 2021-05-28 \n", + "25 2021-08-31 \n", + "26 2021-07-02 \n", + "27 2022-09-02 \n", + "28 2021-08-24 \n", + "29 2023-08-31 \n", + "30 2021-08-31 \n", + "31 2022-08-31 \n", + "32 2022-09-02 \n", + "33 2022-06-17 \n", + "34 2021-07-31 \n", + "35 2024-08-30 \n", + "36 2021-07-31 \n", + "37 2021-08-04 \n", + "38 2023-07-28 \n", + "39 2021-07-30 \n", + "40 2021-08-27 \n", + "41 2022-09-02 \n", + "42 2021-08-31 \n", + "43 2023-09-01 \n", + "44 2021-08-24 \n", + "45 2022-06-16 \n", + "46 2021-09-06 \n", + "47 2022-07-31 \n", + "48 2021-10-08 \n", + "49 2023-09-01 \n", + "50 2022-09-30 \n", + "51 2023-08-31 \n", + "52 2023-08-31 \n", + "53 2021-07-31 \n", + "54 2022-06-17 \n", + "55 2022-01-04 \n", + "56 2022-12-31 \n", + "57 2021-09-03 \n", + "58 2021-09-10 \n", + "59 2022-09-02 \n", + "60 2023-08-31 \n", + "61 2022-06-30 \n", + "62 2023-09-01 \n", + "63 2022-08-31 \n", + "64 2022-09-02 \n", + "65 2022-08-26 \n", + "\n", + " Ore di assistenza \\n ai sensi della delibera\\nn. 666/2019 \\\n", + "8 836.25 \n", + "9 935.25 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 690.00 \n", + "13 965.50 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 274.50 \n", + "17 592.00 \n", + "18 1269.75 \n", + "19 372.00 \n", + "20 1010.50 \n", + "21 652.00 \n", + "22 940.50 \n", + "23 1338.75 \n", + "24 575.50 \n", + "25 812.25 \n", + "26 428.00 \n", + "27 474.50 \n", + "28 979.00 \n", + "29 263.50 \n", + "30 806.50 \n", + "31 1016.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 488.00 \n", + "35 140.00 \n", + "36 587.75 \n", + "37 573.00 \n", + "38 1211.75 \n", + "39 476.00 \n", + "40 469.50 \n", + "41 200.25 \n", + "42 973.00 \n", + "43 493.50 \n", + "44 562.50 \n", + "45 427.25 \n", + "46 950.75 \n", + "47 1405.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 496.00 \n", + "54 108.50 \n", + "55 1353.25 \n", + "56 1643.50 \n", + "57 695.00 \n", + "58 879.50 \n", + "59 276.00 \n", + "60 1328.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1152.50 \n", + "\n", + " Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020 \\\n", + "8 132.00 \n", + "9 21.25 \n", + "10 0.00 \n", + "11 0.00 \n", + "12 30.75 \n", + "13 22.50 \n", + "14 0.00 \n", + "15 0.00 \n", + "16 39.00 \n", + "17 22.00 \n", + "18 31.50 \n", + "19 20.00 \n", + "20 22.00 \n", + "21 30.00 \n", + "22 0.00 \n", + "23 110.00 \n", + "24 0.00 \n", + "25 76.00 \n", + "26 20.00 \n", + "27 78.00 \n", + "28 110.00 \n", + "29 58.50 \n", + "30 0.00 \n", + "31 60.00 \n", + "32 0.00 \n", + "33 0.00 \n", + "34 20.00 \n", + "35 0.00 \n", + "36 23.50 \n", + "37 20.00 \n", + "38 0.00 \n", + "39 20.00 \n", + "40 23.50 \n", + "41 0.00 \n", + "42 95.00 \n", + "43 78.00 \n", + "44 22.50 \n", + "45 0.00 \n", + "46 32.00 \n", + "47 35.00 \n", + "48 0.00 \n", + "49 0.00 \n", + "50 0.00 \n", + "51 0.00 \n", + "52 0.00 \n", + "53 20.00 \n", + "54 0.00 \n", + "55 32.50 \n", + "56 132.00 \n", + "57 63.00 \n", + "58 21.25 \n", + "59 0.00 \n", + "60 25.00 \n", + "61 0.00 \n", + "62 0.00 \n", + "63 0.00 \n", + "64 0.00 \n", + "65 66.00 \n", + "\n", + " Ore totali rendicontate per il 2021 \n", + "8 968.25 \n", + "9 956.50 \n", + "10 605.50 \n", + "11 84.00 \n", + "12 720.75 \n", + "13 988.00 \n", + "14 462.50 \n", + "15 1314.50 \n", + "16 313.50 \n", + "17 614.00 \n", + "18 1301.25 \n", + "19 392.00 \n", + "20 1032.50 \n", + "21 682.00 \n", + "22 940.50 \n", + "23 1448.75 \n", + "24 575.50 \n", + "25 888.25 \n", + "26 448.00 \n", + "27 552.50 \n", + "28 1089.00 \n", + "29 322.00 \n", + "30 806.50 \n", + "31 1076.00 \n", + "32 616.00 \n", + "33 95.00 \n", + "34 508.00 \n", + "35 140.00 \n", + "36 611.25 \n", + "37 593.00 \n", + "38 1211.75 \n", + "39 496.00 \n", + "40 493.00 \n", + "41 200.25 \n", + "42 1068.00 \n", + "43 571.50 \n", + "44 585.00 \n", + "45 427.25 \n", + "46 982.75 \n", + "47 1440.00 \n", + "48 632.50 \n", + "49 248.25 \n", + "50 213.00 \n", + "51 543.75 \n", + "52 706.00 \n", + "53 516.00 \n", + "54 108.50 \n", + "55 1385.75 \n", + "56 1775.50 \n", + "57 758.00 \n", + "58 900.75 \n", + "59 276.00 \n", + "60 1353.50 \n", + "61 543.00 \n", + "62 401.50 \n", + "63 1734.00 \n", + "64 629.50 \n", + "65 1218.50 " + ] + }, + "execution_count": 202, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dfx" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "a0f879dc", + "metadata": {}, + "outputs": [], + "source": [ + "df2 = df[\"Ore contrattualizzate non erogate\\nai sensi della delibera\\nn. 1025/2020\"].notnull()\n", + "df2 = df[c].groupby(\"Comune\", as_index = False)[\"Codice fiscale\"].count()" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "7fb21c72", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ComuneCodice fiscale
0Bolzano34
\n", + "
" + ], + "text/plain": [ + " Comune Codice fiscale\n", + "0 Bolzano 34" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38880426", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.2" + }, + "toc-autonumbering": true, + "toc-showcode": true + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pages/dataout.csv b/pages/dataout.csv new file mode 100644 index 0000000000000000000000000000000000000000..0589c95003deb9f17b74921cacd3e57c74f9f141 --- /dev/null +++ b/pages/dataout.csv @@ -0,0 +1,188 @@ +,filename,Cognome e nome bambino,Ente,Comune,Data di nascita,Codice fiscale,Assistente domiciliare all'infanzia,Comune di residenza assistente domiciliare all'infanzia,Data inizio contratto (o data inizio assistenza se diversa),GiorniAssistenzaAnnoRiferimento,"Data fine contratto +(o data fine assistenza se diversa) *","Ore di assistenza + ai sensi della delibera +n. 666/2019","Ore contrattualizzate non erogate +ai sensi della delibera +n. 543_1025/2020",massimo543,"Ore contrattualizzate non erogate +ai sensi della delibera +n. 733/2020","Ore contrattualizzate non erogate +nella fase 2 (finanziamento compensativo)",Ore totali rendicontate per il 2020,errCodFisc1,errCodFisc2,errAgeChild,errInizioMinoreFine,errErrorePresenza,errErroreDati543,errFineAssistenzaMax4Anni,errKindergarten_1,errKindergarten_2,errErroreFinanziamentoCompensativo,errErroreFinanziamentoCompensativo2,errErroreCovid,errErroreCovid2,errErroreCovid3,errErroreCovid4,errFehlerEingewöhnung,errFehlerEingewöhnung543Lockdown,errFehlerEingewöhnung543Notbetreuung,errGesamtstundenVertragszeitraum,errSuperatoOreMassime1920,errBambinoInPiuComuni,errPresentiAnnotazioni,errOreRendicontateZero,errSommaOre,errMassimoFC,gg1,gg2,gg3,inizioNorm,fineNorm +9,Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx,Ajardi Josef,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ahrntal,2019-10-02,JRDJSF19R02B220Y,Kirchler Judith,St. Peter In Ahrntal,2020-02-24,312,2020-12-31,641.5,194.5,233,0,50.75,886.75,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-02-24,2020-12-31 +31,Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx,Ruiu Nina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ahrntal,2017-03-25,RUINNI17C65B220Y,Kirchler Irmgard,Ahrntal,2018-03-01,287,2020-10-13,554.75,176.5,202,0,54.5,785.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-13 +10,Erklärung Gemeinden Jahr 2020 Algund.xlsx,Bertagnolli Julius,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Algund,2017-08-10,BRTJLS17M10I729H,Troger Moser Anna,Algund,2020-03-20,42,2020-04-30,0.0,73.0,0,0,0.0,73.0,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-03-20,2020-04-30 +11,Erklärung Gemeinden Jahr 2020 Algund.xlsx,Ciaramella Lageder Giacomo Clemens,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Algund,2019-12-22,CRMGMC19T22F132F,Borarosova Zaneta ,Meran,2020-09-07,56,2020-11-01,68.5,0.0,0,0,0.0,68.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-09-07,2020-11-01 +16,Erklärung Gemeinden Jahr 2020 Algund.xlsx,Gruber Emma,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Algund,2018-05-27,GRBMME18E67F132P,Troger Moser Anna,Algund,2020-03-02,305,2020-12-31,753.5,267.0,300,0,96.5,1117.0,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +18,Erklärung Gemeinden Jahr 2020 Algund.xlsx,Hölzl Felicia Victoria,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Algund,2017-11-16,HLZFCV17S56F132E,Willibald Maria Anna,Algund,2019-09-30,366,2020-12-31,716.5,220.0,236,0,119.5,1056.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +21,Erklärung Gemeinden Jahr 2020 Algund.xlsx,Maturilli Anna Maria,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Algund,2017-06-23,MTRNMR17H63F132N,De Arruda Ruth,Meran,2020-01-01,268,2020-09-24,427.0,237.5,164,0,-70.0,594.5,,,,,,,,,True,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-09-24 +8,Erklärung Gemeinden Jahr 2020 Auer.xlsx,Billi Lorenzo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Auer,2020-02-12,BLLLNZ20B12A952J,Huber Melanie,Margreid,2020-11-09,53,2020-12-31,70.75,24.0,14,0,0.0,94.75,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Bozen.xlsx,Alia Amelia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bozen,2018-11-21,LAIMLA18S61A952S,Kienzl Karin Anna,Leifers,2019-04-15,277,2020-10-03,856.75,250.0,297,0,7.0,1113.75,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-10-03 +15,Erklärung Gemeinden Jahr 2020 Bozen.xlsx,Huber Anna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bozen,2018-11-15,HBRNNA18S55A952Y,Molon Karoline,Bozen,2020-03-02,305,2020-12-31,426.5,209.0,233,0,210.5,846.0,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,2,2020-03-02,2020-12-31 +22,Erklärung Gemeinden Jahr 2020 Bozen.xlsx,Pircher Elsa Katharina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bozen,2020-02-15,PRCLKT20B55I729Y,Kaserer Monika,Schlanders,2020-11-03,59,2020-12-31,71.0,16.0,11,0,0.0,87.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-03,2020-12-31 +25,Erklärung Gemeinden Jahr 2020 Bozen.xlsx,Stampfl Johanna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bozen,2017-01-07,STMJNN17A47A952V,Plattner Julia,Terlan,2019-09-02,244,2020-08-31,248.0,104.0,114,0,24.0,376.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-31 +31,Erklärung Gemeinden Jahr 2020 Bozen.xlsx,Viaro Camilla,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bozen,2016-10-24,VRICLL16R64L378G,Molon Karoline,Bozen,2018-09-03,63,2020-03-03,188.0,0.0,0,0,0.0,188.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-03-03 +14,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Keim Iaco,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2017-07-27,KMECIA17L27B160E,Stablum Martina,Brixen,2019-10-09,127,2020-05-06,90.0,108.0,0,0,54.0,252.0,,,,,,,,,,,True,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-06 +21,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Lüling Gabriel,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2017-02-23,LLNGRL17B23B160G,Stablum Martina,Brixen,2018-10-29,251,2020-09-07,278.75,195.25,161,0,73.0,547.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-07 +25,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Oschmann Carl Cosimo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2017-07-23,SCHCLC17L23B160P,Stablum Martina,Brixen,2019-10-18,267,2020-09-23,280.5,136.0,130,0,56.0,472.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-23 +30,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Platter Felix,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2017-04-28,PLTFLX17D28B160Z,Agreiter Theolinda,Brixen,2018-07-16,267,2020-09-23,268.0,108.0,123,0,69.0,445.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-23 +52,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Weissteiner Maximilian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2018-07-16,WSSMML18L16B160Z,Tschiggfrei Monika,Brixen,2020-11-09,53,2020-12-31,58.25,9.0,10,0,0.0,67.25,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +53,Erklärung Gemeinden Jahr 2020 Brixen.xlsx,Witcher Noah Sebastian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Brixen,2017-03-04,WTCNSB17C04B160X,Tschiggfrei Monika,Brixen,2020-01-14,256,2020-09-25,286.5,100.0,116,0,16.0,402.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-14,2020-09-25 +9,Erklärung Gemeinden Jahr 2020 Burgstall.xlsx,Mazohl Mari,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Burgstall,2018-09-24,MZHMRA18P64F132P,Czuchin Rosa ,Lana,2019-04-23,235,2020-08-22,329.5,165.75,179,0,75.0,570.25,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-08-22 +11,Erklärung Gemeinden Jahr 2020 Burgstall.xlsx,Vent Ludwig,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Burgstall,2018-09-17,VNTLWG18P17F132O,Troger Moser Anna,Algund,2020-03-02,305,2020-12-31,480.5,156.0,186,0,56.0,692.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +16,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Burkhart Nele,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2017-02-01,BRKNLE17B41B220I,Keppel Carina,Gais,2018-08-27,251,2020-09-07,641.5,208.0,226,0,-81.0,768.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-07 +23,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Gatterer Banna Amira,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2017-04-03,GTTMRA17D43B220Y,Oberleiter Maria Magdalena ,Percha,2019-01-08,366,2020-12-31,834.0,275.0,286,0,168.5,1277.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +43,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Longo Giada,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2017-05-28,LNGGDI17E68B220Z,Keppel Carina,Gais,2018-09-14,366,2020-12-31,582.5,102.0,163,0,47.0,731.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +51,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Obgriesser Niklas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2017-02-26,BGRNLS17B26B220E,Bacher Helga,Bruneck,2017-12-04,252,2020-09-08,293.0,183.5,188,0,164.5,641.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-08 +65,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Schwärzer Anna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2019-10-28,SCHNNA19R68B220L,Gartner Annemarie,Bruneck,2020-08-24,7,2020-08-30,20.5,0.0,0,0,0.0,20.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-08-24,2020-08-30 +68,Erklärung Gemeinden Jahr 2020 Bruneck.xlsx,Steger Fiona,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Bruneck,2019-05-23,STGFNI19E63B220P,Gartner Sabine,Pfalzen,2020-03-04,64,2020-05-06,3.75,130.0,0,0,0.0,133.75,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-03-04,2020-05-06 +10,Erklärung Gemeinden Jahr 2020 Deutschnofen.xlsx,Werner Emma,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Deutschnofen,2017-12-27,WRNMME17T67A952M,Zelger Sara,Karneid,2020-09-01,122,2020-12-31,213.0,16.0,15,0,0.0,229.0,,,,,,,,,True,,,,,,,,,,,,,,,,,0,8,0,2020-09-01,2020-12-31 +11,Erklärung Gemeinden Jahr 2020 Eppan.xlsx,Cellamare Camilla,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Eppan,2017-09-20,CLLCLL17P60F132P,Mathà Renate,Eppan,2020-07-21,56,2020-09-14,151.0,0.0,0,0,0.0,151.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-07-21,2020-09-14 +18,Erklärung Gemeinden Jahr 2020 Eppan.xlsx,Fabris Nathan,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Eppan,2020-02-09,FBRNHN20B09F132A,Oberhofer Kathrin,Eppan,2020-11-09,53,2020-12-31,54.0,12.0,9,0,0.0,66.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +21,Erklärung Gemeinden Jahr 2020 Eppan.xlsx,Messner Jakob,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Eppan,2017-11-30,MSSJKB17S30F132S,Ambach Maria,Eppan,2019-08-01,262,2020-09-18,825.75,363.5,365,0,105.25,1294.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +24,Erklärung Gemeinden Jahr 2020 Eppan.xlsx,Pramstrahler Josef,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Eppan,2019-06-13,PRMJSF19H13A952Z,Mathà Renate,Eppan,2020-03-16,16,2020-03-31,0.0,23.0,0,0,0.0,23.0,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-03-16,2020-03-31 +10,Erklärung Gemeinden Jahr 2020 Feldthurns.xlsx,Crepaz Amelie,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Feldthurns,2018-01-01,CRPMLA18A41B160K,Zanesco Lisa,Feldthurns,2020-03-02,305,2020-12-31,358.75,141.5,153,0,56.5,556.75,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,2,2020-03-02,2020-12-31 +13,Erklärung Gemeinden Jahr 2020 Gais.xlsx,Schwärzer Anna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gais,2019-10-28,SCHNNA19R68B220L,Gartner Annemarie,Bruneck,2020-08-31,123,2020-12-31,250.0,0.0,16,0,0.0,250.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-08-31,2020-12-31 +14,Erklärung Gemeinden Jahr 2020 Gargazon.xlsx,Malfatti Jonas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gargazon,2017-05-18,MLFJNS17E18F132I,Schölzhorn Sonja,Gargazon,2019-01-02,265,2020-09-21,371.75,189.0,194,0,134.0,694.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-21 +18,Erklärung Gemeinden Jahr 2020 Gargazon.xlsx,Santner Lenz,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gargazon,2018-01-30,SNTLNZ18A30F132R,Ladurner Irene,Marling,2020-11-12,50,2020-12-31,63.0,17.5,12,0,0.0,80.5,,,,,,,,,,,,,,,,,,True,,,True,,,,,0,8,0,2020-11-12,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Graun.xlsx,Edobor Evidence,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Graun im Vinschgau,2019-07-19,DBRVNC19L59A952Z,Oswald Maria Pia,Mals i.V.,2020-11-03,59,2020-12-31,21.0,98.75,20,0,0.0,119.75,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,2,2020-11-03,2020-12-31 +10,Erklärung Gemeinden Jahr 2020 Graun.xlsx,Imonsili Mercy,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Graun im Vinschgau,2018-04-23,MNSMCY18D63A952N,Oswald Maria Pia,Mals i.V.,2020-06-22,193,2020-12-31,369.0,92.0,23,0,0.0,461.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,2,2020-06-22,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Gsies.xlsx,Haller Toni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gsies,2016-12-14,HLLTNO16T14B220U,Kargruber Maria,Gsies,2020-07-06,31,2020-08-05,105.0,0.0,0,0,0.0,105.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-07-06,2020-08-05 +9,Erklärung Gemeinden Jahr 2020 Gsies.xlsx,Haller Toni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gsies,2016-12-14,HLLTNO16T14B220U,Kargruber Maria,Gsies,2019-04-03,187,2020-07-05,130.5,189.0,221,0,240.0,559.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-05 +14,Erklärung Gemeinden Jahr 2020 Gsies.xlsx,Seiwald Silas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Gsies,2016-11-08,SWLSLS16S08B220U,Auer Petra,Percha,2019-07-04,247,2020-09-03,598.5,237.25,272,0,72.75,908.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-03 +11,Erklärung Gemeinden Jahr 2020 Hafling.xlsx,Eschgfaeller Marie,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Hafling,2017-12-22,SCHMRA17T62A952K,Plattner Martina,Hafling,2019-07-01,366,2020-12-31,888.0,264.0,280,0,97.75,1249.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +14,Erklärung Gemeinden Jahr 2020 Kaltern.xlsx,Hafner Paul,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kaltern,2018-05-20,HFNPLA18E20F132Q,Oberhofer Kathrin,Eppan,2020-02-18,79,2020-05-06,12.25,117.0,0,0,0.0,129.25,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-02-18,2020-05-06 +32,Erklärung Gemeinden Jahr 2020 Kaltern.xlsx,Sinn Sebastian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kaltern,2019-03-22,SNNSST19C22A952Q,Peterlin Verena,Kaltern,2020-03-09,120,2020-07-06,0.0,105.0,0,0,94.0,199.0,,,,,,,,,,True,,,,True,True,,,,,,,,,,,0,0,0,2020-03-09,2020-07-06 +9,Erklärung Gemeinden Jahr 2020 Karneid.xlsx,Bozzano Pietro,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Karneid,2017-01-26,BZZPTR17A26B160X,Covi Sibylle,Karneid,2018-10-08,127,2020-05-06,174.0,210.0,0,0,0.0,384.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-06 +13,Erklärung Gemeinden Jahr 2020 Karneid.xlsx,Rieder Fabian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Karneid,2017-01-08,RDRFBN17A08B160U,Covi Sibylle,Karneid,2020-01-20,108,2020-05-06,68.0,104.0,0,0,0.0,172.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-20,2020-05-06 +9,Erklärung Gemeinden Jahr 2020 Kastelbell-Tschars.xlsx,Corduneanu Dorian *,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kastelbell-Tschars,2017-04-05,CRDDRN17D05I729Y,Prantl Stefanie,Kastelbell/Tschars,2018-01-05,127,2020-05-06,151.5,108.0,0,0,0.0,259.5,,,,,,,,,,,,,,,,,,,,,,True,,,,0,0,0,2020-01-01,2020-05-06 +10,Erklärung Gemeinden Jahr 2020 Kastelruth.xlsx,Gostner Noah,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kastelruth,2017-12-18,GSTNHO17T18B160K,Bernard Nadine,Kastelruth,2019-03-21,276,2020-10-02,674.0,258.0,283,0,125.25,1057.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-02 +14,Erklärung Gemeinden Jahr 2020 Kiens.xlsx,Hochgruber Raphael,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kiens,2017-11-04,HCHRHL17S04B220O,Leiter Manuela,St.Lorenzen,2019-09-16,366,2020-12-31,768.5,230.0,239,0,69.0,1067.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +21,Erklärung Gemeinden Jahr 2020 Kiens.xlsx,Weger Mathe Elisabeth,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kiens,2018-08-11,WGRMHL18M51B220M,Tasser Margit,St.Lorenzen,2020-11-09,53,2020-12-31,89.5,27.5,17,0,0.0,117.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Klausen.xlsx,Bekoe Lucia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Klausen,2017-10-10,BKELCU17R50A952D,Duchova Dana,Lajen,2020-01-18,253,2020-09-26,886.0,414.0,389,0,30.0,1330.0,,,,,,,,,True,,,,,,,,,,True,,,,,,,74,0,0,2020-01-18,2020-09-26 +9,Erklärung Gemeinden Jahr 2020 Klausen.xlsx,Frei Gasser Mia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Klausen,2017-03-25,FRGMIA17C65B160L,Agreiter Theolinda,Brixen,2018-06-25,260,2020-09-16,450.0,180.0,202,0,80.0,710.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-16 +8,Erklärung Gemeinden Jahr 2020 Kurtatsch.xlsx,Barcatta Lisa,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Kurtatsch,2018-11-07,BRCLSI18S47A952V,Peer Petra,Kurtatsch,2020-11-09,53,2020-12-31,98.0,26.25,18,0,0.0,124.25,,,,,,,,,,,,,,,,,,True,,,True,,,,,0,8,0,2020-11-09,2020-12-31 +10,Erklärung Gemeinden Jahr 2020 Lana.xlsx,D´Altri Stella,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2019-02-21,DLTSLL19B61A944K,Andergassen Ruth,Lana,2020-02-18,79,2020-05-06,19.0,122.5,0,0,0.0,141.5,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-02-18,2020-05-06 +12,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Gasser Lara,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2017-02-08,GSSLRA17B48F132D,Kuprian Alexandra,Lana,2020-08-03,40,2020-09-11,137.75,0.0,0,0,0.0,137.75,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-08-03,2020-09-11 +13,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Goegele Maria,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2016-11-22,GGLMRA16S62F132J,Kofler Gertraud ,Lana,2018-07-16,178,2020-06-26,117.5,90.0,114,0,67.0,274.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-26 +28,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Orlando Amy,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2017-05-06,RLNMYA17E46F132T,Schwienbacher Hanna,Lana,2019-10-01,160,2020-06-08,124.0,102.0,126,0,48.0,274.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-06-08 +29,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Pejic Milica,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2017-06-08,PJCMLC17H48F132R,Lasakova Ivana,Lana,2019-03-26,260,2020-09-16,473.0,161.0,187,0,26.0,660.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-16 +43,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Wassler Alex,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2018-06-02,WSSLXA18H02A952T,Troger Moser Anna,Algund,2020-03-02,217,2020-10-04,7.0,110.5,88,0,143.0,260.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-03-02,2020-10-04 +45,Erklärung Gemeinden Jahr 2020 Lana.xlsx,Wenter Leo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Lana,2017-08-01,WNTLEO17M01F132R,Kofler Gertraud ,Lana,2018-05-15,274,2020-09-30,644.0,231.0,257,0,77.0,952.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-30 +8,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Alia Amelia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2018-11-21,LAIMLA18S61A952S,Kienzl Karin Anna,Leifers,2020-10-04,89,2020-12-31,288.0,66.0,39,0,0.0,354.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,2,2020-10-04,2020-12-31 +9,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Barbi Serena,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2017-10-25,BRBSRN17R65A952R,Huber Jessica,Pfatten,2018-08-27,366,2020-12-31,1070.5,318.0,350,0,138.0,1526.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,2,2020-01-01,2020-12-31 +11,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Cellamare Camilla,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2017-09-20,CLLCLL17P60F132P,Mathà Renate,Eppan,2019-09-02,202,2020-07-20,317.0,192.5,195,0,24.0,533.5,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-07-20 +13,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Coser Anna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2019-05-14,CSRNNA19E54F132F,Huber Jessica,Pfatten,2020-03-02,305,2020-12-31,339.0,121.75,139,0,46.5,507.25,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,2,2020-03-02,2020-12-31 +14,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Coser Arthur,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2017-07-18,CSRRHR17L18F132W,Huber Jessica,Pfatten,2018-01-11,366,2020-12-31,446.5,136.25,143,0,44.0,626.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,2,2020-01-01,2020-12-31 +36,Erklärung Gemeinden Jahr 2020 Leifers.xlsx,Todde Nicoló,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Leifers,2019-04-28,TDDNCL19D28A952R,Kienzl Karin Anna,Leifers,2020-08-24,130,2020-12-31,601.75,92.75,53,0,0.0,694.5,,,,,,,,,,,,,,,,,,,True,,,,,,,0,8,2,2020-08-24,2020-12-31 +17,Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx,Punter Julius,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Mals i. V.,2017-06-12,PNTJLS17H12A952S,Weisenhorn Annamaria,Mals i.V.,2020-03-03,11,2020-03-13,6.0,18.0,0,0,0.0,24.0,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-03-03,2020-03-13 +18,Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx,Punter Emil,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Mals i. V.,2017-06-12,PNTMLE17H12A952H,Weisenhorn Annamaria,Mals i.V.,2020-03-03,11,2020-03-13,6.0,18.0,0,0,0.0,24.0,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-03-03,2020-03-13 +24,Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx,Usom Best Daniel,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Mals i. V.,2017-03-15,SMBDNL17C15A952L,Oswald Maria Pia,Mals i.V.,2020-05-18,110,2020-09-04,213.0,0.0,0,0,0.0,213.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-05-18,2020-09-04 +8,Erklärung Gemeinden Jahr 2020 Margreid.xlsx,Barcatta Lisa,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Margreid,2018-11-07,BRCLSI18S47A952V,Peer Petra,Kurtatsch,2019-09-24,182,2020-06-30,175.75,170.0,135,0,-13.75,332.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-06-30 +9,Erklärung Gemeinden Jahr 2020 Margreid.xlsx,Barcatta Lisa,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Margreid,2018-11-07,BRCLSI18S47A952V,Peer Petra,Kurtatsch,2020-07-01,131,2020-11-08,341.5,0.0,0,0,0.0,341.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-07-01,2020-11-08 +19,Erklärung Gemeinden Jahr 2020 Marling.xlsx,Ladurner Moritz,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Marling,2017-02-09,LDRMTZ17B09F132D,Leiter Julia,Marling,2019-01-11,267,2020-09-23,606.25,243.75,271,0,130.25,980.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-23 +21,Erklärung Gemeinden Jahr 2020 Marling.xlsx,Matzoll Rene,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Marling,2017-03-30,MTZRNE17C30F132A,Alber Karolina,Meran,2019-08-01,304,2020-10-30,559.0,108.0,166,0,17.0,684.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-30 +8,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Agostinetto Matti,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2020-02-09,GSTMTT20B09A952T,Kienzl Martina Rosa,Meran,2020-10-26,67,2020-12-31,63.0,15.0,9,0,0.0,78.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-10-26,2020-12-31 +9,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Agostinetto Levi,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-02-06,GSTLVE17B06A952V,Kienzl Martina Rosa,Meran,2017-10-02,240,2020-08-27,345.75,178.5,197,0,115.5,639.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-27 +26,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Burger Karin,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2019-05-20,BRGKRN19E60I729G,Prantl Hildburg,Meran,2020-11-09,53,2020-12-31,62.0,18.0,12,0,0.0,80.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +38,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Ciaramella Lageder Giacomo Clemens,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2019-12-22,CRMGMC19T22F132F,Borarosova Zaneta ,Meran,2020-11-02,60,2020-12-31,156.0,24.0,24,0,0.0,180.0,,,,,,,,,,,,,,,,,,True,,,True,,,,,0,8,0,2020-11-02,2020-12-31 +41,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Costa Yasmina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-05-20,CSTYMN17E60F132Y,Prantl Hildburg,Meran,2020-07-01,80,2020-09-18,241.5,0.0,0,0,0.0,241.5,,,,,,,,,True,,,,,,,,,,,,,,,,,0,0,0,2020-07-01,2020-09-18 +58,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Doliana Mia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2016-12-31,DLNMIA16T71A952X,Theiner Sylvia,Meran,2017-09-18,219,2020-08-06,231.0,175.0,200,0,186.0,592.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-06 +86,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Huber Alexander,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2018-07-27,HBRLND18L27Z102R,Muszala Annekathrin,Meran,2020-02-20,316,2020-12-31,600.5,286.5,281,0,198.5,1085.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-02-20,2020-12-31 +93,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Massei Damian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-11-29,MSSDMN17S29Z102Y,Schwienbacher Hanna,Lana,2019-09-10,366,2020-12-31,592.5,200.0,193,0,70.0,862.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +96,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Maturilli Anna Maria,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-06-23,MTRNMR17H63F132N,De Arruda Ruth,Meran,2019-05-13,1,2020-01-01,50.0,0.0,0,0,335.0,385.0,,,,,,,,,,,True,True,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-01-01 +97,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Mazohl Mari,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2018-09-24,MZHMRA18P64F132P,Czuchin Rosa ,Lana,2020-08-23,131,2020-12-31,251.75,20.5,16,0,0.0,272.25,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-08-23,2020-12-31 +99,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Niederstaetter Leo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-06-28,NDRLEO17H28F132T,De Arruda Ruth,Meran,2020-11-10,52,2020-12-31,230.5,0.0,35,0,0.0,230.5,,,,,,,,,True,,,,,,,,,,,,,,,,,0,8,0,2020-11-10,2020-12-31 +100,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Niederstaetter Leo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-06-28,NDRLEO17H28F132T,Christanell Elisabeth,Meran,2019-05-02,304,2020-10-30,815.0,241.0,266,0,37.0,1093.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-30 +103,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Orlando Amy,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-05-06,RLNMYA17E46F132T,Schwienbacher Hanna,Lana,2020-06-09,114,2020-09-30,138.0,0.0,0,0,0.0,138.0,,,,,,,,,True,,,,,,,,,,,,True,,,,,0,0,0,2020-06-09,2020-09-30 +110,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Perillo Zwink Noah Leon,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-01-15,PRLNLN17A15F132L,Corazza Rosemarie,Meran,2020-07-01,66,2020-09-04,148.5,0.0,0,0,0.0,148.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-07-01,2020-09-04 +111,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Perillo Zwink Noah Leon,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-01-15,PRLNLN17A15F132L,Corazza Rosemarie,Meran,2017-11-02,121,2020-04-30,180.25,203.25,0,0,0.0,383.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-04-30 +114,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Pfattner Jonas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2016-11-25,PFTJNS16S25A952D,Theiner Sylvia,Meran,2018-09-03,255,2020-09-11,696.25,329.25,356,0,203.5,1229.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-11 +115,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Pfattner Jonas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2016-11-25,PFTJNS16S25A952D,Radina Germana ,Meran,2020-08-31,5,2020-09-04,37.0,0.0,0,0,0.0,37.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-08-31,2020-09-04 +121,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Prevedello Timo,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-12-12,PRVTMI17T12F132L,Borarosova Zaneta ,Meran,2018-09-17,366,2020-12-31,1357.0,349.0,384,0,10.5,1716.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +133,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Scano Nicole,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-04-24,SCNNCL17D64F132B,Borarosova Zaneta ,Meran,2018-07-03,274,2020-09-30,389.0,130.0,138,0,-6.5,512.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-30 +143,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Stanzel Amira,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-05-13,STNMRA17E53F132I,Radina Germana ,Meran,2018-07-02,266,2020-09-22,445.0,215.0,182,0,-5.0,655.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-22 +147,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Stragenegg Krieg Paul,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-02-14,STRPLA17B14F132K,Corazza Rosemarie,Meran,2018-02-01,255,2020-09-11,535.0,252.5,274,0,159.0,946.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-11 +154,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Usom Best Daniel,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2017-03-15,SMBDNL17C15A952L,Christanell Elisabeth,Meran,2019-10-21,31,2020-01-31,121.0,0.0,0,0,0.0,121.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-01-31 +158,Erklärung Gemeinden Jahr 2020 Meran.xlsx,Vassanelli Noah,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Meran,2016-10-13,VSSNHO16R13F132P,Schwalt Kathrin,Meran,2017-07-19,247,2020-09-03,256.0,172.0,182,0,180.0,608.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-03 +9,Erklärung Gemeinden Jahr 2020 Mölten.xlsx,Gruber Emil,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Moelten,2016-12-12,GRBMLE16T12F132N,Duregger Evi,Voeran,2018-02-01,251,2020-09-07,270.5,108.0,115,0,13.5,392.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-07 +10,Erklärung Gemeinden Jahr 2020 Mölten.xlsx,Thaler Leia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Moelten,2019-01-28,THLLEI19A68F132X,Plattner Julia,Terlan,2020-02-17,319,2020-12-31,702.25,201.5,229,0,-13.0,890.75,,,,,,,,,,,,,,,,,True,,,,,,,,,74,8,0,2020-02-17,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Moos In Passeier.xlsx,Gufler Lina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Moos in Passeier,2018-07-17,GFLLNI18L57F132G,Trocker Christine,St. Leonhard i.P.,2020-03-05,63,2020-05-06,0.0,149.0,0,0,0.0,149.0,,,,,,,,,,,,,,True,True,,True,,,,,,,,,0,0,0,2020-03-05,2020-05-06 +11,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Blaas Jakob,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2016-10-29,BLSJKB16R29I729Q,Prantl Stefanie,Kastelbell/Tschars,2020-01-20,12,2020-01-31,48.75,0.0,0,0,0.0,48.75,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-20,2020-01-31 +12,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Blaas Jakob,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2016-10-29,BLSJKB16R29I729Q,Rabensteiner Maria,Naturns,2017-08-10,259,2020-09-15,498.0,117.0,150,0,-89.0,526.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-15 +14,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Burger Linnea,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2018-03-08,BRGLNN18C48I729E,Prantl Stefanie,Kastelbell/Tschars,2020-09-01,122,2020-12-31,296.5,30.0,21,0,0.0,326.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-09-01,2020-12-31 +15,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Burger Linnea,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2018-03-08,BRGLNN18C48I729E,Blaas Veronika,Kastelbell/Tschars,2020-12-22,1,2020-12-22,5.0,0.0,0,0,0.0,5.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-12-22,2020-12-22 +16,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Burger Linnea,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2018-03-08,BRGLNN18C48I729E,Blaas Veronika,Kastelbell/Tschars,2020-10-23,2,2020-10-24,5.0,0.0,0,0,0.0,5.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-10-23,2020-10-24 +40,Erklärung Gemeinden Jahr 2020 Naturns.xlsx,Schnitzer Lia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Naturns,2018-09-22,SCHLIA18P62F132S,Pixner Silvia,St. Leonhard in Passeier,2020-11-09,53,2020-12-31,92.0,27.5,18,0,0.0,119.5,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Natz Schabs.xlsx,Battaglia Mattia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Natz Schabs,2017-09-08,BTTMTT17P08B160L,Salcher Andrea,Mühlbach,2020-02-20,77,2020-05-06,24.75,247.25,0,0,0.0,272.0,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-02-20,2020-05-06 +9,Erklärung Gemeinden Jahr 2020 Olang.xlsx,Winkler Paula,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Olang,2017-10-02,WNKPLA17R42B220L,Oberleiter Maria Magdalena ,Percha,2019-10-23,366,2020-12-31,601.0,175.25,202,0,126.0,902.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Partschings.xlsx,Abler Sophie,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Partschins,2016-12-28,BLRSPH16T68F132B,Tappeiner Heidemarie,Partschins,2017-09-01,304,2020-10-30,427.5,169.0,178,0,136.5,733.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-30 +9,Erklärung Gemeinden Jahr 2020 Partschings.xlsx,Audino Dennis,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Partschins,2018-03-15,DNADNS18C15F132Y,Rabensteiner Maria,Naturns,2020-03-09,58,2020-05-05,0.0,98.0,0,0,0.0,98.0,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-03-09,2020-05-05 +12,Erklärung Gemeinden Jahr 2020 Partschings.xlsx,Burger Linnea,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Partschins,2018-03-08,BRGLNN18C48I729E,Prantl Stefanie,Kastelbell/Tschars,2019-11-15,244,2020-08-31,471.25,171.75,204,0,30.75,673.75,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-08-31 +23,Erklärung Gemeinden Jahr 2020 Partschings.xlsx,Pircher Rafael Stefan,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Partschins,2017-08-21,PRCRLS17M21I729J,Prantl Stefanie,Kastelbell/Tschars,2020-05-18,110,2020-09-04,322.25,81.0,0,0,0.0,403.25,,,,,,,,,,,,,,True,,,,,,,,,,,,0,0,0,2020-05-18,2020-09-04 +14,Erklärung Gemeinden Jahr 2020 Percha.xlsx,Premstaller Emmi,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Percha,2019-09-25,PRMMME19P65B220I,Auer Petra,Percha,2020-02-28,129,2020-07-05,4.0,122.0,156,0,146.0,272.0,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-02-28,2020-07-05 +9,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Ellecosta Emely,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2017-11-09,LLCMLY17S49B220J,Leiter Manuela,St.Lorenzen,2020-05-13,233,2020-12-31,487.25,26.25,19,0,63.0,576.5,,,,,,,,,True,True,,,,,True,,,,,,True,,,,,0,8,0,2020-05-13,2020-12-31 +18,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Oberhollenzer Ben,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2017-09-04,BRHBNE17P04B220J,Oberleiter Maria Magdalena ,Percha,2018-09-05,366,2020-12-31,935.0,156.0,247,0,12.0,1103.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +21,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Priller Yara,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2017-04-29,PRLYRA17D69B220C,Winding Helga,Pfalzen,2018-07-02,366,2020-12-31,409.5,125.0,134,0,65.5,600.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +24,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Sevcikova Nadia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2017-01-30,SVCNDA17A70B220F,Volgger Theresia,Vintl,2017-12-11,127,2020-05-06,336.0,275.5,0,0,0.0,611.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-06 +27,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Weger Sophia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2018-04-06,WGRSPH18D46B220D,Rederlechner Angelika,Sand in Taufers,2020-09-04,119,2020-12-31,150.0,18.0,11,0,0.0,168.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-09-04,2020-12-31 +28,Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx,Weger Toni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfalzen,2017-02-05,WGRTNO17B05B160N,Winding Helga,Pfalzen,2019-07-01,230,2020-08-17,217.0,100.0,123,0,68.0,385.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-17 +12,Erklärung Gemeinden Jahr 2020 Pfatten.xlsx,Volante Vittorio,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfatten,2017-02-01,VLNVTR17B01A952B,Radicchi Daniela,Pfatten,2018-07-09,127,2020-05-06,228.0,258.0,0,0,0.0,486.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-06 +15,Erklärung Gemeinden Jahr 2020 Pfitsch.xlsx,Whitecotton Leopold Harrison,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Pfitsch,2018-02-20,WHTLLD18B20Z112Z,Oberstaller Agathe,Pfitsch,2020-09-15,108,2020-12-31,174.0,30.0,15,0,0.0,204.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-09-15,2020-12-31 +9,Erklärung Gemeinden Jahr 2020 Prad a.Stj..xlsx,Ennemoser Ella,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Prad a Stj,2017-01-20,NNMLLE17A60A952M,Weisenhorn Annamaria,Mals i.V.,2019-07-15,121,2020-04-30,152.5,174.0,0,0,0.0,326.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-04-30 +16,Erklärung Gemeinden Jahr 2020 Rasen-Antholz.xlsx,Taschler Anton,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Rasen/Antholz,2017-07-08,TSCNTN17L08B220M,Oberleiter Maria Magdalena ,Percha,2018-06-25,366,2020-12-31,780.5,232.0,248,0,94.75,1107.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +8,Erklärung Gemeinden Jahr 2020 Ratschings.xlsx,Fiechter Emil,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ratschings,2017-01-12,FCHMLE17A12B160W,Thaler Petra,Ratschings,2020-01-03,251,2020-09-09,272.0,124.5,146,0,101.5,498.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-03,2020-09-09 +11,Erklärung Gemeinden Jahr 2020 Ratschings.xlsx,Pillon Luna,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ratschings,2019-03-01,PLLLNU19C41B160R,Thaler Petra,Ratschings,2020-03-23,284,2020-12-31,544.5,7.0,20,0,25.0,576.5,,,,,,,,,,True,,,,,True,,,,,,,,,,,0,8,2,2020-03-23,2020-12-31 +13,Erklärung Gemeinden Jahr 2020 Ratschings.xlsx,Santer Zoey,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ratschings,2019-05-11,SNTZYO19E51B160D,Thaler Petra,Ratschings,2020-03-16,291,2020-12-31,521.75,20.75,19,0,23.75,566.25,,,,,,,,,,True,,,,,True,,,,,,,,,,,0,8,2,2020-03-16,2020-12-31 +15,Erklärung Gemeinden Jahr 2020 Ratschings.xlsx,Walter Moritz,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ratschings,2016-08-02,WLTMTZ16M02M067H,Oberstaller Agathe,Pfitsch,2017-12-01,185,2020-07-03,470.75,268.5,315,0,49.0,788.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-03 +9,Erklärung Gemeinden Jahr 2020 Riffian.xlsx,Gruber Karolina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Riffian,2017-01-30,GRBKLN17A70F132K,Trientbacher Margit,Riffian,2018-03-01,248,2020-09-04,429.75,193.5,195,0,33.25,656.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-04 +12,Erklärung Gemeinden Jahr 2020 Riffian.xlsx,Pichler Simon,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Riffian,2019-07-15,PCHSMN19L15F132H,Trientbacher Margit,Riffian,2020-03-03,304,2020-12-31,360.5,168.0,198,0,207.25,735.75,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-03,2020-12-31 +10,Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx,Ausserhofer Matthias,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sand in Taufers,2017-11-09,SSRMTH17S09B220Q,Rederlechner Angelika,Sand in Taufers,2019-05-06,366,2020-12-31,394.0,116.25,118,0,20.25,530.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +11,Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx,Eder Bruno,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sand in Taufers,2019-06-09,DREBRN19H09B220H,Berger Michaela,Sand in Taufers,2020-03-04,303,2020-12-31,448.5,113.0,149,0,-10.5,551.0,,,,,,,,,,,,,,,,,True,,,,,,,,,74,8,0,2020-03-04,2020-12-31 +12,Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx,Ellecosta Emely,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sand in Taufers,2017-11-09,LLCMLY17S49B220J,Leiter Manuela,St.Lorenzen,2019-05-06,133,2020-05-12,135.0,157.5,0,0,0.0,292.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-05-12 +17,Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx,Niederkofler Josef,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sand in Taufers,2017-01-20,NDRJSF17A20B220Z,Rederlechner Angelika,Sand in Taufers,2018-11-05,212,2020-07-30,232.0,140.0,155,0,72.0,444.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-30 +21,Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx,Weger Sophia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sand in Taufers,2018-04-06,WGRSPH18D46B220D,Rederlechner Angelika,Sand in Taufers,2019-09-09,247,2020-09-03,260.0,104.0,118,0,32.0,396.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-09-03 +10,Erklärung Gemeinden Jahr 2020 Sarntal.xlsx,Desaler Viktoria,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sarntal,2017-01-11,DSLVTR17A51A952V,Gufler Petra,Sarntal,2018-12-03,163,2020-06-11,242.75,189.0,216,0,45.0,476.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-11 +26,Erklärung Gemeinden Jahr 2020 Sarntal.xlsx,Thaler Nils,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sarntal,2017-11-11,THLNLS17S11A952H,Frenzel Karina,Sarntal,2020-03-23,39,2020-04-30,0.0,57.0,0,0,0.0,57.0,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-03-23,2020-04-30 +11,Erklärung Gemeinden Jahr 2020 Schenna.xlsx,Illmer Rafael,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schenna,2019-02-10,LLMRFL19B10F132U,Mittelberger Maria,Schenna,2020-03-16,291,2020-12-31,443.5,139.0,20,0,164.0,746.5,,,,,,,,,,True,,,,,True,,,,,,,,,,,0,8,0,2020-03-16,2020-12-31 +16,Erklärung Gemeinden Jahr 2020 Schenna.xlsx,Pföstl Philipp,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schenna,2017-02-08,PFSPLP17B08F132P,Unterholzner Tanja,Schenna,2018-02-05,273,2020-09-29,394.5,129.0,147,0,19.5,543.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-29 +8,Erklärung Gemeinden Jahr 2020 Schlanders.xlsx,Doda Denis,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schlanders,2017-07-05,DDODNS17L05I729E,Kaserer Monika,Schlanders,2018-03-20,262,2020-09-18,528.0,280.0,286,0,205.5,1013.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +21,Erklärung Gemeinden Jahr 2020 Schlanders.xlsx,Thoman Aimar Amalia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schlanders,2017-12-29,THMMLA17T69I729V,Kaserer Monika,Schlanders,2018-08-07,260,2020-09-16,471.25,227.5,241,0,148.5,847.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-16 +22,Erklärung Gemeinden Jahr 2020 Schlanders.xlsx,Trafoier Alex,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schlanders,2017-11-27,TRFLXA17S27I729K,Stecher Romina,Schlanders,2019-04-01,261,2020-09-17,425.0,170.0,143,0,-90.0,505.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-17 +12,Erklärung Gemeinden Jahr 2020 Schnals.xlsx,Gorfer Florian,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schnals,2018-05-23,GRFFRN18E23I729P,Graiss Lisa,Schnals,2020-05-04,179,2020-10-29,249.75,12.0,0,0,0.0,261.75,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-05-04,2020-10-29 +15,Erklärung Gemeinden Jahr 2020 Schnals.xlsx,Woerndle Paul,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Schnals,2017-12-13,WRNPLA17T13I729Z,Graiss Lisa,Schnals,2020-11-02,60,2020-12-31,62.0,18.0,13,0,0.0,80.0,,,,,,,,,True,,,,,,,,,True,,,,,,,,0,8,2,2020-11-02,2020-12-31 +11,Erklärung Gemeinden Jahr 2020 St. Leonhard in Passeier.xlsx,Gumpold Marius,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Leonhard in Passeier,2017-08-28,GMPMRS17M28F132X,Trocker Christine,St. Leonhard in P.,2020-12-01,31,2020-12-31,69.0,0.0,0,0,0.0,69.0,,,,,,,,,True,,,,,,,,,,,,,,,,,0,0,0,2020-12-01,2020-12-31 +13,Erklärung Gemeinden Jahr 2020 St. Lorenzen.xlsx,Huber David,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Lorenzen,2016-11-18,HBRDVD16S18B220L,Leiter Manuela,St.Lorenzen,2018-09-17,244,2020-08-31,418.75,143.5,170,0,-0.5,561.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-31 +16,Erklärung Gemeinden Jahr 2020 St. Lorenzen.xlsx,Moosbrugger Theresa,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Lorenzen,2017-02-02,MSBTRS17B42Z102X,Leiter Manuela,St.Lorenzen,2019-03-11,219,2020-08-06,200.75,104.0,120,0,51.5,356.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-06 +13,Erklärung Gemeinden Jahr 2020 St. Martin In Passeier.xlsx,Kofler Andreas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Martin in Passeier,2017-11-23,KFLNRS17S23F132N,Schweigl Simone,St. Martin In P.,2020-09-09,114,2020-12-31,200.0,13.75,15,0,0.0,213.75,,,,,,,,,True,,,,,,,,,,,,,,,,,0,8,0,2020-09-09,2020-12-31 +11,Erklärung Gemeinden Jahr 2020 St. Pankraz Ulten.xlsx,Matzoll Simon,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Pankraz Ulten,2016-12-01,MTZSMN16T01F132M,Zöschg Gertrud,St. Pankraz Ulten,2019-08-26,52,2020-02-21,122.5,0.0,0,0,0.0,122.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-02-21 +19,Erklärung Gemeinden Jahr 2020 St. Pankraz Ulten.xlsx,Schwienbacher Ida,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,St. Pankraz Ulten,2019-08-08,SCHDIA19M48F132M,Zöschg Gertrud,St. Pankraz Ulten,2020-01-29,106,2020-05-13,31.0,119.0,0,0,71.0,221.0,,,,,,,,,,,True,,,,,,,,,,True,,,,,0,0,0,2020-01-29,2020-05-13 +15,Erklärung Gemeinden Jahr 2020 Sterzing.xlsx,Whitecotton Leopold Harrison,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Sterzing,2018-02-20,WHTLLD18B20Z112Z,Oberstaller Agathe,Pfitsch,2019-09-17,90,2020-03-30,116.0,44.0,0,0,0.0,160.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-03-30 +10,Erklärung Gemeinden Jahr 2020 Taufers im Münstertal.xlsx,Imonsili Mercy,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Taufers i. M.,2018-04-23,MNSMCY18D63A952N,Oswald Maria Pia,Mals i.V.,2020-05-18,35,2020-06-21,58.0,0.0,0,0,0.0,58.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-05-18,2020-06-21 +11,Erklärung Gemeinden Jahr 2020 Taufers im Münstertal.xlsx,Malloth Daniel,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Taufers i. M.,2017-07-10,MLLDNL17L10I729Y,Weisenhorn Annamaria,Mals i.V.,2020-02-13,184,2020-08-14,170.0,168.5,189,0,131.5,470.0,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-02-13,2020-08-14 +9,Erklärung Gemeinden Jahr 2020 Tiers.xlsx,Lunger Ida,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tiers,2017-11-11,LNGDIA17S51A952F,Lunger Alexandra,Tiers,2018-09-03,268,2020-09-24,300.0,117.0,128,0,49.5,466.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-24 +11,Erklärung Gemeinden Jahr 2020 Tiers.xlsx,Mentzel Katharina,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tiers,2017-01-15,MNTKHR17A55A952Q,Lunger Alexandra,Tiers,2019-02-14,127,2020-05-06,189.5,202.5,0,0,0.0,392.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-06 +14,Erklärung Gemeinden Jahr 2020 Tiers.xlsx,Rieder Isabel,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tiers,2016-08-10,RDRSBL16M50A952F,Lunger Alexandra,Tiers,2018-11-05,17,2020-01-17,32.5,0.0,0,0,0.0,32.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-01-17 +10,Erklärung Gemeinden Jahr 2020 Tirol.xlsx,Prantl Rosa,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tirol,2018-02-09,PRNRSO18B49F132Z,Schwalt Kathrin,Meran,2020-03-03,65,2020-05-06,6.25,112.5,0,0,0.0,118.75,,,,,,,,,,,,,,,,,True,,,,,,,,,0,0,0,2020-03-03,2020-05-06 +10,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Niederstaetter Leni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2016-12-19,NDRLNE16T59A952N,Wolf Alexandra,Tscherms,2019-05-02,154,2020-06-02,87.5,108.0,113,0,40.0,235.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-02 +11,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Niederstaetter Leni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2016-12-19,NDRLNE16T59A952N,Wolf Alexandra,Tscherms,2020-06-03,93,2020-09-03,113.5,0.0,0,0,24.5,138.0,,,,,,,,True,,True,,,,,,,,,,,,,,,,0,0,0,2020-06-03,2020-09-03 +12,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Niederstaetter Toni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2016-12-19,NDRTNO16T19A952B,Wolf Alexandra,Tscherms,2019-05-02,154,2020-06-02,87.5,108.0,113,0,40.0,235.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-02 +13,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Niederstaetter Toni,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2016-12-19,NDRTNO16T19A952B,Wolf Alexandra,Tscherms,2020-06-03,93,2020-09-03,113.5,0.0,0,0,24.5,138.0,,,,,,,,True,,True,,,,,,,,,,,,,,,,0,0,0,2020-06-03,2020-09-03 +14,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Pircher Paul,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2016-11-29,PRCPLA16S29F132U,Wolf Alexandra,Tscherms,2017-08-07,211,2020-07-29,301.5,204.0,233,0,160.0,665.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-29 +15,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Santner Lenz,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2018-01-30,SNTLNZ18A30F132R,Ladurner Irene,Marling,2019-02-18,316,2020-11-11,379.0,164.5,162,0,151.0,694.5,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-11-11 +16,Erklärung Gemeinden Jahr 2020 Tscherms.xlsx,Scheibenhoffer Alexander,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tscherms,2017-02-12,SCHLND17B12F132N,Hofer Carina,Marling,2020-02-11,218,2020-09-15,350.5,210.0,190,0,0.0,560.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-02-11,2020-09-15 +9,Erklärung Gemeinden Jahr 2020 Tramin.xlsx,Frei Juri,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tramin,2018-05-29,FREJRU18E29A952R,Peer Petra,Kurtatsch,2020-03-10,57,2020-05-05,0.0,90.0,0,0,0.0,90.0,,,,,,,,,,,,,,True,True,,,,,,,,,,,0,0,0,2020-03-10,2020-05-05 +11,Erklärung Gemeinden Jahr 2020 Tramin.xlsx,Kajana Mia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Tramin,2018-08-03,KJNMIA18M43A952A,Ambach Maria,Eppan,2019-08-06,138,2020-05-17,99.5,144.75,0,0,66.25,310.5,,,,,,,,,,,True,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-05-17 +9,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Gamper Klaus,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2016-12-18,GMPKLS16T18F132L,Zöschg Rita ,Ulten,2020-02-18,78,2020-05-05,25.5,256.0,0,0,0.0,281.5,,,,,,,,True,,,,,,,,,True,,,,,,,,,0,0,0,2020-02-18,2020-05-05 +11,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Gamper Martha,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2019-04-07,GMPMTH19D47F132J,Zöschg Rita ,Ulten,2020-02-18,210,2020-09-14,20.5,256.0,232,0,382.0,658.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-02-18,2020-09-14 +15,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Karlegger Svenja Heidrun,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2018-09-09,KRLSNJ18P49I729Y,Unterholzner Vera,Ulten,2020-03-02,227,2020-10-14,211.25,102.0,123,0,65.25,378.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-03-02,2020-10-14 +17,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Pircher Hannes,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2017-03-08,PRCHNS17C08F132K,Zöschg Rita ,Ulten,2019-05-15,366,2020-12-31,833.0,156.0,213,0,-38.0,951.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +24,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Schwienbacher Ida,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2019-08-08,SCHDIA19M48F132M,Zöschg Gertrud,St. Pankraz Ulten,2020-05-14,232,2020-12-31,314.5,19.0,7,0,-118.0,215.5,,,,,,,,,,,,,,,True,,,,,,True,,,,,0,8,0,2020-05-14,2020-12-31 +25,Erklärung Gemeinden Jahr 2020 Ulten.xlsx,Trafojer Jakob,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Ulten,2016-11-22,TRFJKB16S22F132Q,Zöschg Rita ,Ulten,2019-06-06,247,2020-09-03,395.5,129.5,144,0,-44.0,481.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-03 +11,Erklärung Gemeinden Jahr 2020 Villnöss.xlsx,Mayer Fabienne,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Villnöss,2017-07-27,MYRFNN17L67B160A,Aukenthaler Roswitha,Villnöss,2019-05-02,261,2020-09-17,425.75,122.5,150,0,-18.5,529.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-17 +17,Erklärung Gemeinden Jahr 2020 Vintl.xlsx,Mor Nadyn,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Vintl,2016-09-25,MRONYN16P65B160C,Huber Barbara,Vintl,2018-08-24,194,2020-07-12,127.5,109.5,125,0,92.25,329.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-12 +18,Erklärung Gemeinden Jahr 2020 Vintl.xlsx,Mor Nadyn,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Vintl,2016-09-25,MRONYN16P65B160C,Huber Barbara,Vintl,2020-07-13,60,2020-09-10,128.25,0.0,0,0,0.0,128.25,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-07-13,2020-09-10 +20,Erklärung Gemeinden Jahr 2020 Vintl.xlsx,Ploner Simon,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Vintl,2017-01-18,PLNSMN17A18B220Q,Volgger Theresia,Vintl,2018-05-07,241,2020-08-28,392.0,104.0,157,0,16.5,512.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +12,Erklärung Gemeinden Jahr 2020 Völs am Schlern.xlsx,Villgrattner Jonas,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Völs am Schlern,2017-01-09,VLLJNS17A09B160F,Lunger Alexandra,Tiers,2020-08-13,30,2020-09-11,76.0,0.0,0,0,0.0,76.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-08-13,2020-09-11 +9,Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx,Dejori Pia,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Welschnofen,2017-01-27,DJRPIA17A67A952Q,Kompatscher Sarah,Welschnofen,2018-11-05,261,2020-09-17,308.25,117.0,136,0,56.0,481.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-17 +12,Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx,Kircher Lena,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Welschnofen,2017-02-13,KRCLNE17B53B160I,Kompatscher Sarah,Welschnofen,2018-06-26,258,2020-09-14,989.75,280.5,342,0,-77.0,1193.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-14 +13,Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx,Kohler Mali,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Welschnofen,2017-01-31,KHLMLA17A71A952X,Kompatscher Sarah,Welschnofen,2018-12-17,101,2020-04-10,129.0,77.0,0,0,0.0,206.0,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-04-10 +19,Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx,Vieider Stina Marie,Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben,Welschnofen,2018-08-16,VDRSNM18M56B160V,Kompatscher Sarah,Welschnofen,2020-10-27,66,2020-12-31,72.0,12.0,12,0,0.0,84.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,2,2020-10-27,2020-12-31 diff --git a/pages/dataout.xlsx b/pages/dataout.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..98ff276580cd034be0e0a69086194c9bdc7b121a Binary files /dev/null and b/pages/dataout.xlsx differ diff --git a/pages/errorfiles/.DS_Store b/pages/errorfiles/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9f0a8edf75ae05e239d5a558a2fe20846464e532 Binary files /dev/null and b/pages/errorfiles/.DS_Store differ diff --git "a/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Ahrntal_corr.xlsx" "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Ahrntal_corr.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..810ab374b4ca788d7b821e42af3c8908c332b794 Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Ahrntal_corr.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Leifers.xlsx" "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Leifers.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..98b0c91d0c6bb0532e8b5be4d3c16628c0d6fdfe Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Leifers.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..5b178c6a6ed40e77c73cebf950c178a3937c7e0f Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung Gemeinden Jahr 2020 Tramin.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung_Gemeinde_Aldein_2020.xlsx" "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Aldein_2020.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..1d6e70b55359978c22220b0f032890a3ed4e11fb Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Aldein_2020.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung_Gemeinde_Brixen_2020.xlsx" "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Brixen_2020.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..4cdeed1f3598b9bd0fffe86521e695b590d35a7c Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Brixen_2020.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020.xlsx" "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..5bdcd053a6c1354fd0abe70c3ac768646ea65320 Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020.xlsx" differ diff --git "a/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020_2.xlsx" "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020_2.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..27d43f0d3be667b706bccc9d8c59bd9b3967b4e5 Binary files /dev/null and "b/pages/errorfiles/Erkla\314\210rung_Gemeinde_Klausen_2020_2.xlsx" differ diff --git a/pages/errorfiles/Fehler Anwesenheit.xlsx b/pages/errorfiles/Fehler Anwesenheit.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ba2eb87295f12c5a4a500c421ada76e0230de6d3 Binary files /dev/null and b/pages/errorfiles/Fehler Anwesenheit.xlsx differ diff --git a/pages/errorfiles/Fehler Daten 543.xlsx b/pages/errorfiles/Fehler Daten 543.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d96dc40ffd60233b5e1c1bb2b31bad0f34e42750 Binary files /dev/null and b/pages/errorfiles/Fehler Daten 543.xlsx differ diff --git "a/pages/errorfiles/Fehler Eingewo\314\210hnung.xlsx" "b/pages/errorfiles/Fehler Eingewo\314\210hnung.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..c24cf3e4d5c925a9e372d83b8f26c9815bb62b0f Binary files /dev/null and "b/pages/errorfiles/Fehler Eingewo\314\210hnung.xlsx" differ diff --git a/pages/errorfiles/Fehler Gesamtsstundenzahl-Kind3x.xlsx b/pages/errorfiles/Fehler Gesamtsstundenzahl-Kind3x.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..00158378571a429e7638d2da63ac3d43a905d439 Binary files /dev/null and b/pages/errorfiles/Fehler Gesamtsstundenzahl-Kind3x.xlsx differ diff --git "a/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel1.xlsx" "b/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel1.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..9bcbec18b65a92efef8d51d0a6409713c5709313 Binary files /dev/null and "b/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel1.xlsx" differ diff --git "a/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel2.xlsx" "b/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel2.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..fce978524bd78166e1dd836d9994a9f62a46f891 Binary files /dev/null and "b/pages/errorfiles/Fehler Gesamtsstundenzahl-u\314\210ber meherere excel2.xlsx" differ diff --git a/pages/errorfiles/Fehler Gesamtsstundenzahl.xlsx b/pages/errorfiles/Fehler Gesamtsstundenzahl.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6e22b67915b61581d9fbc33ffdbb47b7da9c980e Binary files /dev/null and b/pages/errorfiles/Fehler Gesamtsstundenzahl.xlsx differ diff --git a/pages/errorfiles/Fehler Proportion Gesamtstunden-Vertragzeitraum.xlsx b/pages/errorfiles/Fehler Proportion Gesamtstunden-Vertragzeitraum.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d49516314b741fe84e1add0f7f0a86fa43bce6be Binary files /dev/null and b/pages/errorfiles/Fehler Proportion Gesamtstunden-Vertragzeitraum.xlsx differ diff --git a/pages/errorfiles/Fehler codice fiscale kind 2 mal.xlsx b/pages/errorfiles/Fehler codice fiscale kind 2 mal.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..243e361cfcfddef55b1135d780654c053e1f6507 Binary files /dev/null and b/pages/errorfiles/Fehler codice fiscale kind 2 mal.xlsx differ diff --git a/pages/errorfiles/Fehler covid 2.xlsx b/pages/errorfiles/Fehler covid 2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1f2696f654d00ba0aff4ee94fd21885008d62ec8 Binary files /dev/null and b/pages/errorfiles/Fehler covid 2.xlsx differ diff --git a/pages/errorfiles/Fehler covid.xlsx b/pages/errorfiles/Fehler covid.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b8e2e2ad356f22ebf77a4d00a2bf539445b78850 Binary files /dev/null and b/pages/errorfiles/Fehler covid.xlsx differ diff --git a/pages/errorfiles/Fehler data nascita.xlsx b/pages/errorfiles/Fehler data nascita.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..79bd40029a59dcdeb2d8b2b79bd2a3c276b9b567 Binary files /dev/null and b/pages/errorfiles/Fehler data nascita.xlsx differ diff --git a/pages/errorfiles/Fehler finanziamento compensativo.xlsx b/pages/errorfiles/Fehler finanziamento compensativo.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..82fa37ba3327cd26890d68630f4e15d0865c3690 Binary files /dev/null and b/pages/errorfiles/Fehler finanziamento compensativo.xlsx differ diff --git a/pages/errorfiles/Fehler_VertragsDaten.xlsx b/pages/errorfiles/Fehler_VertragsDaten.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6433d443c1c118b838976ac71cb4deec2fc42b76 Binary files /dev/null and b/pages/errorfiles/Fehler_VertragsDaten.xlsx differ diff --git a/pages/errorfiles/Kontrolle Kindergarten 1.xlsx b/pages/errorfiles/Kontrolle Kindergarten 1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6e3b429ba057ab79a951db7247be02dd86b89a90 Binary files /dev/null and b/pages/errorfiles/Kontrolle Kindergarten 1.xlsx differ diff --git a/pages/errorfiles/Kontrolle Kindergarten 2.xlsx b/pages/errorfiles/Kontrolle Kindergarten 2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..41dab9d6d8a2c20f193c49870e3c343d54fdd452 Binary files /dev/null and b/pages/errorfiles/Kontrolle Kindergarten 2.xlsx differ diff --git a/pages/errorfiles/Kontrolle Listen TM 2020.docx b/pages/errorfiles/Kontrolle Listen TM 2020.docx new file mode 100644 index 0000000000000000000000000000000000000000..a56ed495459b08d68bfe575dc9cddd68cff4368a Binary files /dev/null and b/pages/errorfiles/Kontrolle Listen TM 2020.docx differ diff --git a/pages/errorfiles/Report annuale comune di Bolzano.xlsx b/pages/errorfiles/Report annuale comune di Bolzano.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..193b42468d01d2a2dba15aa9989f725da3d8afb1 Binary files /dev/null and b/pages/errorfiles/Report annuale comune di Bolzano.xlsx differ diff --git a/pages/errorfiles/Report annuale comune di Bolzano2.xlsx b/pages/errorfiles/Report annuale comune di Bolzano2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..02b2f301f4e1374f100ca24f7aee6250a428c575 Binary files /dev/null and b/pages/errorfiles/Report annuale comune di Bolzano2.xlsx differ diff --git a/pages/errorfiles/Report annuale comune di Laives.xlsx b/pages/errorfiles/Report annuale comune di Laives.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f7e83391c80c83a1b0ae931f505c8d9cfb96f0b3 Binary files /dev/null and b/pages/errorfiles/Report annuale comune di Laives.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Bolzano.xlsx b/pages/errorfiles/pippo/Report annuale Bolzano.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..26b799674c026d7d891226f72c82878007834657 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Bolzano.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Cornedo all'Isarco.xlsx b/pages/errorfiles/pippo/Report annuale Cornedo all'Isarco.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a5b7fde967e6f3a62db9fdc5a92a23134b355ab5 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Cornedo all'Isarco.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Egna.xlsx b/pages/errorfiles/pippo/Report annuale Egna.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3b998541a25f106f72abf7cc6b4115dc6d7bf128 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Egna.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Laives.xlsx b/pages/errorfiles/pippo/Report annuale Laives.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..013b673d738eb83cbc8e5628b688ce2770a63383 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Laives.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Laives_BZ.xlsx b/pages/errorfiles/pippo/Report annuale Laives_BZ.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..608288d97a0b4672ebc51009ca844a38f2221e60 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Laives_BZ.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Merano.xlsx b/pages/errorfiles/pippo/Report annuale Merano.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6024e577b0538c2bbc9d921c9473bab03eba9c8c Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Merano.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Ora.xlsx b/pages/errorfiles/pippo/Report annuale Ora.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c1fa12ec660c24fd51ac355a0ac054a3c8e140d8 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Ora.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Scena.xlsx b/pages/errorfiles/pippo/Report annuale Scena.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5bacc7b891eed2963fbf4fc9b2213991ce4d3596 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Scena.xlsx differ diff --git a/pages/errorfiles/pippo/Report annuale Terlano.xlsx b/pages/errorfiles/pippo/Report annuale Terlano.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4d7b5358063dd2118f2513bc219c517b5e1a7429 Binary files /dev/null and b/pages/errorfiles/pippo/Report annuale Terlano.xlsx differ diff --git a/pages/errorfilesKitas/EsempioTimeSeries.xlsx b/pages/errorfilesKitas/EsempioTimeSeries.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b82d8b376ca807f97f9cc1c938096022e532b5b2 Binary files /dev/null and b/pages/errorfilesKitas/EsempioTimeSeries.xlsx differ diff --git a/pages/errorfilesKitas/EsempioTimeSeries2.xlsx b/pages/errorfilesKitas/EsempioTimeSeries2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7afc92da9bbfb2272cc009a470e9f2cd1894fb00 Binary files /dev/null and b/pages/errorfilesKitas/EsempioTimeSeries2.xlsx differ diff --git a/pages/errorfilesKitas/Fehler Angabe data inizio oder fine.xlsx b/pages/errorfilesKitas/Fehler Angabe data inizio oder fine.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8e89e06cb7c20a54ff463766117ce8a6ba770837 Binary files /dev/null and b/pages/errorfilesKitas/Fehler Angabe data inizio oder fine.xlsx differ diff --git a/pages/errorfilesKitas/Fehler Angaben Gemeindekind.xlsx b/pages/errorfilesKitas/Fehler Angaben Gemeindekind.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..15cdfb864421a5759b5cebd9eb2ca91672f4a161 Binary files /dev/null and b/pages/errorfilesKitas/Fehler Angaben Gemeindekind.xlsx differ diff --git a/pages/errorfilesKitas/Fehler Kind Mehrfachnennung 2.xlsx b/pages/errorfilesKitas/Fehler Kind Mehrfachnennung 2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fc094d1b1aac7195fd632556cfa8638598a4cc48 Binary files /dev/null and b/pages/errorfilesKitas/Fehler Kind Mehrfachnennung 2.xlsx differ diff --git a/pages/errorfilesKitas/Fehler Kind Mehrfachnennung.xlsx b/pages/errorfilesKitas/Fehler Kind Mehrfachnennung.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5e23991ef33c54d66a40af30af7c2d1537ad7c26 Binary files /dev/null and b/pages/errorfilesKitas/Fehler Kind Mehrfachnennung.xlsx differ diff --git a/pages/errorfilesKitas/Fehler elenco utenti precedenti.xlsx b/pages/errorfilesKitas/Fehler elenco utenti precedenti.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f5a48c7e7bc8731e12d0df5eb9c964525395fe7d Binary files /dev/null and b/pages/errorfilesKitas/Fehler elenco utenti precedenti.xlsx differ diff --git a/pages/errorfilesKitas/Fehler fine vor Lockdown.xlsx b/pages/errorfilesKitas/Fehler fine vor Lockdown.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..cca0cd2a66f5e8b574131159e20df68b076fc0c5 Binary files /dev/null and b/pages/errorfilesKitas/Fehler fine vor Lockdown.xlsx differ diff --git a/pages/errorfilesKitas/Fehler inizio-Beitragsjahr.xlsx b/pages/errorfilesKitas/Fehler inizio-Beitragsjahr.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d3927442ed781844127cfc4dee0c03d7c77085ac Binary files /dev/null and b/pages/errorfilesKitas/Fehler inizio-Beitragsjahr.xlsx differ diff --git a/pages/errorfilesKitas/Fehler inserimento post Notbetreuung.xlsx b/pages/errorfilesKitas/Fehler inserimento post Notbetreuung.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..72ff8e6fbfdbe5a40d0b0676c539b5f5765c7262 Binary files /dev/null and b/pages/errorfilesKitas/Fehler inserimento post Notbetreuung.xlsx differ diff --git a/pages/errorfilesKitas/Fehler tipo kitas.xlsx b/pages/errorfilesKitas/Fehler tipo kitas.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b75dbcb3ff84392165a4224d6a466df11aa2c491 Binary files /dev/null and b/pages/errorfilesKitas/Fehler tipo kitas.xlsx differ diff --git a/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noGestore.xlsx b/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noGestore.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3137546f823dafee8f9fbbf5c41a9bb42b514635 Binary files /dev/null and b/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noGestore.xlsx differ diff --git a/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noMicro.xlsx b/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noMicro.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c34de68052a52d140e84e3edd2492a4eb14cf91b Binary files /dev/null and b/pages/errorfilesKitas/prospetto rendicontazione via combattenti 2019_noMicro.xlsx differ diff --git a/pages/errorfilesKitas/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx b/pages/errorfilesKitas/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..508af8421c186907899380e480cf5b966dc9cec1 Binary files /dev/null and b/pages/errorfilesKitas/test rendicontazione microstrutture miste 2019 Fiera Xenia_mss.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler Angabe data inizio oder fine.xlsx b/pages/errorfilesKitas2020/Fehler Angabe data inizio oder fine.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6ba633387e01f0359cc5ae82e5bbc48b0de44eb7 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler Angabe data inizio oder fine.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler Angaben Gemeindekind.xlsx b/pages/errorfilesKitas2020/Fehler Angaben Gemeindekind.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7f5984e617525960799df210a12ad03206cbe197 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler Angaben Gemeindekind.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung 2.xlsx b/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung 2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1821f7950630d10ab3383957b651be6cd0637647 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung 2.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung.xlsx b/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7966fa4080f0ac1d7c846993cd7c115a89f5067b Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler Kind Mehrfachnennung.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler elenco utenti precedenti.xlsx b/pages/errorfilesKitas2020/Fehler elenco utenti precedenti.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f5a48c7e7bc8731e12d0df5eb9c964525395fe7d Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler elenco utenti precedenti.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler fine vor Lockdown.xlsx b/pages/errorfilesKitas2020/Fehler fine vor Lockdown.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..cca0cd2a66f5e8b574131159e20df68b076fc0c5 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler fine vor Lockdown.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler inizio-Beitragsjahr.xlsx b/pages/errorfilesKitas2020/Fehler inizio-Beitragsjahr.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4bc04df83177b288dc548008ae74956134a7d280 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler inizio-Beitragsjahr.xlsx differ diff --git a/pages/errorfilesKitas2020/Fehler inserimento post Notbetreuung.xlsx b/pages/errorfilesKitas2020/Fehler inserimento post Notbetreuung.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..72ff8e6fbfdbe5a40d0b0676c539b5f5765c7262 Binary files /dev/null and b/pages/errorfilesKitas2020/Fehler inserimento post Notbetreuung.xlsx differ diff --git a/pages/errorfilesKitas2021/blatt 1 data fine falsch.xlsx b/pages/errorfilesKitas2021/blatt 1 data fine falsch.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..deb27ffdfad2371ecc959c137e740687354130c4 Binary files /dev/null and b/pages/errorfilesKitas2021/blatt 1 data fine falsch.xlsx differ diff --git a/pages/errorfilesKitas2021/blatt 2 data fine falsch.xlsx b/pages/errorfilesKitas2021/blatt 2 data fine falsch.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..14393a89e0676440efd633e935984f1d29515f18 Binary files /dev/null and b/pages/errorfilesKitas2021/blatt 2 data fine falsch.xlsx differ diff --git "a/pages/errorfilesKitas2021/gemeinde nicht ausgewa\314\210hlt.xlsx" "b/pages/errorfilesKitas2021/gemeinde nicht ausgewa\314\210hlt.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..e08744b59d37a21316527d7b8fce08b8585a458c Binary files /dev/null and "b/pages/errorfilesKitas2021/gemeinde nicht ausgewa\314\210hlt.xlsx" differ diff --git a/pages/errorfilesKitas2021/inizio-fine.xlsx b/pages/errorfilesKitas2021/inizio-fine.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ac5350dd73d8b109e9dc665dd48d0120300ab388 Binary files /dev/null and b/pages/errorfilesKitas2021/inizio-fine.xlsx differ diff --git "a/pages/errorfilesKitas2021/kind auf beide bla\314\210tter.xlsx" "b/pages/errorfilesKitas2021/kind auf beide bla\314\210tter.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..6830fbf032533b0809b2bc9e903fe386b9841317 Binary files /dev/null and "b/pages/errorfilesKitas2021/kind auf beide bla\314\210tter.xlsx" differ diff --git a/pages/errori dopo modifica 2021 - Copy.xlsx b/pages/errori dopo modifica 2021 - Copy.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..adb4ab74b0c6552e19c19b263c791b5ee38343ac Binary files /dev/null and b/pages/errori dopo modifica 2021 - Copy.xlsx differ diff --git a/pages/errori dopo modifica 2021.csv b/pages/errori dopo modifica 2021.csv new file mode 100644 index 0000000000000000000000000000000000000000..6de8867fac60af0b5c987586a0b0e76ce96ed0d7 --- /dev/null +++ b/pages/errori dopo modifica 2021.csv @@ -0,0 +1,100 @@ +Rendiconto per il servizio di assistenza domiciliare all'infanzia - anno 2021,,,,,,,,,,, +,,,,,,,,,,, +Ente gestore:,,,,,,,,,,, +Casa Bimbo ,,,,,,,,,,, +Comune di residenza o di stabile dimora dei bambini assistiti:,,,,,,,,,,, +BOLZANO,,,,,,,,,,, +,,,,,,,,,,, +"Numero +progressivo",Bambino,,Data di nascita,Codice fiscale,Assistente domiciliare all'infanzia,Comune di residenza assistente domiciliare all'infanzia,"Data inizio contratto +(o data inizio assistenza se diversa)","Data fine contratto +(o data fine assistenza se diversa)","Ore di assistenza + ai sensi della delibera +n. 666/2019","Ore contrattualizzate non erogate +ai sensi della delibera +n. 1025/2020",Ore totali rendicontate per il 2021 +,Cognome ,Nome,,,,,,,,, +1,BAH MAMADOU , ADAMA,22/03/2019,BHMDMA19C62A952Y,LOVATO DEBORAH,BOLZANO,19/10/2020,31/08/2022,"836,25","132,00","968,25" +2,TUCCIO, GABRIEL,23/03/2019,TCCGRL19C23A952W,MARTINELLO SILVIA,BOLZANO,08/06/2020,26/08/2022,"935,25","21,25","956,50" +3,GAMBINO, AMBRA,05/05/2018,GMBMBR18E45A952R,MATTEOTTI GIACOMO,BOLZANO,02/09/2019,01/07/2021,"605,5",,"605,50" +4,BISULTANOV, MANSUR,20/08/2019,BSLMSR19M20A952U,IVANOVIC JASNA,MERANO,19.02.2021,08.06.2021,84,,"84,00" +5,DELVAI, MATTEO,18/04/2018,DLVMTT18D18A952J,MATTEOTTI GIACOMO,BOLZANO,19/08/2019,03/07/2021,690,"30,75","720,75" +6,TOSI, SOFIA,02/06/2019,TSOSFO19H42A952Y,MARTINELLO SILVIA,BOLZANO,08/06/2020,02/09/2022,"965,5","22,50","988,00" +7,BRAHAJ, SJORDI,16/08/2020,BRHSRD20M56A952H,KOTI ALMA,BOLZANO,13/09/2021,17/06/2022,"462,5",,"462,50" +8,BUCCELLA, LORENZO,22/10/2019,BCCLNZ19R22F132W,MATTEOTTI GIACOMO,BOLZANO,29/06/2020,31/08/2022,"1314,5",,"1.314,50" +9,FIALCOVSCHI, ALEXANDRU,12/08/2020,FLCLND20M12A952T,LOVATO DEBORAH,BOLZANO,06/09/2021,01/09/2023,"274,5","39,00","313,50" +10,CHIHI, LISA,20/02/2018,CHHLSI18B60A952C,CARUSO MARIA,SCENA,25.02.2021,06/08/2021,592,"22,00","614,00" +11,LANARI, ARIANNA,20/11/2018,LNRRNN18S60A952D,MATTEOTTI GIACOMO,BOLZANO,17/08/2020,02/09/2022,"1269,75","31,50","1.301,25" +12,PATRICELLI, GIULIA,08/03/2020,PTRGLI20C48A952I,IVANOVIC JASNA,SCENA,02.03.2021,30/07/2021,372,"20,00","392,00" +13,SMITH, LIAM,22/03/2019,SMTLMI19C22A952X,KOTI ALMA,BOLZANO,25/08/2020,17/07/2021,"1010,5","22,00","1.032,50" +14,CORNESCU, DANIELE,19/11/2018,CRNDNL18S19A952T,KOTI ALMA,BOLZANO,28/09/2020,25/06/2021,652,"30,00","682,00" +15,SCARATTI, FRANCESCA,10/08/2019,SCRFNC19M50A952J,MOSSA DANIELA,BOLZANO,24.02.2021,29/07/2022,"940,5",,"940,50" +16,BARDINI, MARCO,28/11/2019,BRDMRC19S28A952P,PRAZARU OLENA,BOLZANO,17/08/2020,15/08/2022,"1338,75","110,00","1.448,75" +17,DALL'ARMELLINA, PIETRO,16/05/2019,DLLPTR19E07A952E,MATTEOTTI GIACOMO,BOLZANO,23/09/2019,28/05/2021,"575,5",,"575,50" +18,DE LUCIA, MARTINA,27/02/2018,DLCMTN18B67A952U,LOVATO DEBORAH,BOLZANO,28/09/2020,31/08/2021,"812,25","76,00","888,25" +19,DE PALMA ,ALESSANDRO,12/12/2018,DPLLSN18T12B455O,IVANOVIC JASNA,BOLZANO,29/01/2020,02/07/2021,428,"20,00","448,00" +20,MOHAMMAD SALEEH, BERITAN,04/01/2019,MHMBTN19A44A952V,LOVATO DEBORAH,BOLZANO,20/09/2021,02/09/2022,"474,5","78,00","552,50" +21,PEREZZANI, NOELLE,24/10/2019,PRZNLL19R64A952E,PRAZARU OLENA,BOLZANO,26/08/2020,24/08/2021,979,"110,00","1.089,00" +22,DI FEBBRAIO ,GIUSEPPE,06/02/2020,DFBGPP20B06A952J,LOVATO DEBORAH,BOLZANO,04/10/2021,31/08/2023,"263,50","58,50","322,00" +23,DI PIERRO ,ALICE,24/08/2018,DPRLCA18M64A952O,MOSSA DANIELA,BOLZANO,18/02/2019,31/08/2021,"806,50",,"806,50" +24,DONOLA, MATILDE,15/02/2019,DNLMLD19B55A952X,CAROTTA SILVIA,BOLZANO,28/09/2020,31/08/2022,1016,60,"1.076,00" +25,KHOUIA, HIBA,08/08/2019,KHOHBI19M48A952M,MOSSA DANIELA,RIFIANO,04.02.2021,02/09/2022,616,,"616,00" +26,KANOUNE, MARYEM ELBATOUL,29/03/2019,KNNMYM19C69A952Z,CARUSO MARIA,BOLZANO,06/12/2021,17/06/2022,95,,"95,00" +27,EL HAMDAOUI, NIZAR,06/04/2020,LHMNZR20D60A952K,IVANOVIC JASNA,BOLZANO,04/01/2021,31/07/2021,488,20,"508,00" +28,AYALA GALLEGOS, JAYDEN ,22/11/2020,YLGJDN20S22A952E,CARUSO MARIA,BOLZANO,22/11/2021,30/08/2024,140,,"140,00" +29,GASHI ,AMRA,04/05/2018,GSHMRA18E44A952B,KOTI ALMA/MOSSA DANIELA,BOLZANO,02/09/2019,31/07/2021,"587,75","23,5","611,25" +30,SICOLO, FRANCESCO,06/12/2019,SCLFNC19T06A952K,CARUSO MARIA,BOLZANO,31/08/2020,04/08/2021,573,20,"593,00" +31,DI MARCO, ANITA,11/03/2020,DMRNTA20C51A952W,KOTI ALMA,BOLZANO,31/08/2020,28/07/2023,"1211,75",,"1.211,75" +32,HYSENAJ, ESLI,24/10/2018,HYSSLE18R24A952H,IVANOVIC JASNA,BOLZANO,07/09/2020,30/07/2021,476,20,"496,00" +33,BILAL ,SHAMIR,11/05/2018,BLLSMR18E11A952N,MILITARU ROXANA/CARUSO MARIA,BOLZANO,03/08/2020,27/08/2021,"469,5","23,5","493,00" +34,LLESHI, DANIEL,23/05/2021,LLSDNL21E23A952M,MOSSA DANIELA,SCENA,01.03.2021,02/09/2022,"200,25",,"200,25" +35,LORENZINI ,MARINA,05/11/2018,LRNMRN18S45F132U,LOVATO DEBORAH,BOLZANO,13/01/2020,31/08/2021,973,95,"1.068,00" +36,LOTIERZO ,NICOLO',07/12/2019,LTRNCL19T07A952B,LOVATO DEBORAH,BOLZANO,30/08/2021,01/09/2023,"493,5",78,"571,50" +37,MIRA, TEO,20/05/2019,MRITEO19E20F132A,MOSSA DANIELA,BOLZANO,24/08/2020,24/08/2021,"562,5","22,5","585,00" +38,VENTURINI, AURORA,20/07/2020,VNTRRA20L60A952F,KOTI ALMA,BOLZANO,06/09/2021,16/06/2022,"427,25",,"427,25" +39,MION ,GINEVRA,27/08/2018,MNIGVR18M67A952H,MARTINELLO SILVIA,BOLZANO,10.02.2021,06/09/2021,"950,75",32,"982,75" +40,NEZA, REAN,14/04/2019,NZERNE19D14F257X,KOTI ALMA,BOLZANO,13/10/2020,31/07/2022,1405,35,"1.440,00" +41,PEDINI, LILIANA,26/03/2019,PDNLLN19C66A952Q,MOSSA DANIELA,BOLZANO,02/09/2019,08/10/2021,"632,5",,"632,50" +42,PEREZ PONCE, ELLIE,28/08/2020,PRZLLE20M68A952L,PRAZARU OLENA,BOLZANO,18/10/2021,01/09/2023,"248,25",,"248,25" +43,CIRILLO, JACOPO,26/05/2021,CRLJCP21E26F132N,MARTINELLO SILVIA,BOLZANO,11/10/2021,30/09/2022,"213,00",,"213,00" +44,BAR, NICHOLAS,15/07/2020,BRANHL20L15A952J,MOSSA DANIELA,BOLZANO,30/08/2021,31/08/2023,"543,75",,"543,75" +45,CUEL, MATAN,01/09/2020,CLUMTN20P01A952G,MATTEOTTI GIACOMO,BOLZANO,25/05/2021,31/08/2023,706,,"706,00" +46,POPESCU, MATEI,21/02/2019,PPSMTA19B21A952U,IVANOVIC JASNA,BOLZANO,01/06/2020,31/07/2021,496,20,"516,00" +47,PASCARELLA, DOMENICO,28/03/2019,PSCDNC19C28A952N,CAROTTA SILVIA,BOLZANO,08/11/2021,17/06/2022,"108,5",,"108,50" +48,CAMPARETTO ROCCA ,EDOARDO,19/02/2020,CMPDRD20B19A952O,MARTINELLO SILVIA,BOLZANO,31/08/2020,04/01/2022,"1353,25","32,5","1.385,75" +49,FIORE, LEONARDO,31/12/2019,FRILRD19T31F132G,PRAZARU OLENA,BOLZANO,05/10/2020,31/12/2022,"1643,5",132,"1.775,50" +50,DE COL ,BEATRICE,07/09/2018,DCLBRC18P47A952J,CAROTTA SILVIA,BOLZANO,02/03/2020,03/09/2021,695,63,"758,00" +51,SOTA, PAOLA,29/08/2018,STOPLA18L69A952B,MARTINELLO SILVIA,BOLZANO,23/09/2019,10/09/2021,"879,5","21,25","900,75" +52,TATARI, SAUL,30/12/2019,TTRSLA19T30A952R,MATTEOTTI GIACOMO,BOLZANO,18/10/2021,02/09/2022,276,,"276,00" +53,TRINCO, ANITA,30/05/2020,TRNNTA20E70A952B,CARUSO MARIA,BOLZANO,28/12/2020,31/08/2023,"1328,5",25,"1.353,50" +54,VALLAZZA, ISABEL,23/06/2020,VLLSBL20H63A952Q,CARUSO MARIA,BOLZANO,28/06/2021,30/06/2022,543,,"543,00" +55,MANGIALAIO, LEON,08/10/2020,MNGLNE20R08B220S,MATTEOTTI GIACOMO,BOLZANO,20/09/2021,01/09/2023,"401,5",,"401,50" +56,WEGLEITER, ENEAS,22/10/2018,WGLNSE18R22B160O,MOSSA DANIELA,BOLZANO,13/07/2020,31/08/2022,1734,,"1.734,00" +57,SAID, ZAYD,26/05/2019,SDAZYD19E26G224V,CARUSO MARIA,BOLZANO,30/08/2021,02/09/2022,"629,5",,"629,50" +58,RINDONE, FILIPPO TOMMASO,31/10/2019,RNDFPP19R31A952Y,CAROTTA SILVIA,BOLZANO,31/08/2020,26/08/2022,"1152,5",66,"1.218,50" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,,,"0,00" +,,,,,,,,,"40.952,25","1.612,75","42.565,00" diff --git a/pages/errori dopo modifica 2021.xlsx b/pages/errori dopo modifica 2021.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f76e02b42095b72e4cd942df83f7b39e6b48c55a Binary files /dev/null and b/pages/errori dopo modifica 2021.xlsx differ diff --git a/pages/obsoleti/Betriebliche_Kitas.py b/pages/obsoleti/Betriebliche_Kitas.py new file mode 100644 index 0000000000000000000000000000000000000000..499833966553e905cca07d97baa61448a71d479f --- /dev/null +++ b/pages/obsoleti/Betriebliche_Kitas.py @@ -0,0 +1,406 @@ +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +from datetime import date + +st.set_page_config( + page_title="Controllo Errori Betriebliche Kitas", layout="wide", page_icon="🤗" # 👽 +) + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + # + # distinguiamo tra errori nei file (errData*) ed errori logici (err*) + # + #"dataErrMicrostruttura": "Controllo compilazione microstruttura", + #"dataErrGestore": "Controllo compilazione gestore", + "errNome": "Controllo compilazione cognome e nome bambino", + #"dataErrData": "Controllo formato data inizio e fine assistenza", + "errTipoKitas": "Controllo tipologia Kitas", + "errDataInizioFine": "Controllo data inizio_minore_fine", + "errAnnoRiferimento": "Controllo data inizio per anno riferimento", + # "errOccorrenzeBambino": "Controllo occorrenze bambino", + # "errComuneProvenienza": "Controllo comune provenienza del bambino", + # "errCompilazione666": "Controllo compilazione ore 666", + # "errCompilazione543": "Controllo compilazione ore 543", + # "errOre666": "Controllo ore 666 maggiore di zero", + # "errOre543DataInizio": "Controllo ore 543 su data inizio", + # "errOre543DataFine": "Controllo ore 543 su data fine", + # "errDataInizio2": "Controllo data inizio foglio 1 minore anno riferimento", + # "errOccorrenzeBambinoKitas": "Controllo occorrenze bambino per Kitas", +} + + +def app(): + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori BETRIEBLICHE KITAS (v. 0.0.1)") + dfout = None + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files) + #dfout1, dfout2 = get_data(uploaded_files) + if not dfout1.empty and not dfout2.empty: + #dffinal = + dffinal1 = check_data2(dfout1, checks,'0') + dffinal2 = check_data2(dfout2, checks,'1') + + st.write(dffinal1) + st.write(dffinal2) + + +################################# +## INIZIO CHECKS +################################# + +def errTipoKitas(df, foglio): + condizione1 = df["utente"] != "comunale" + condizione2 = df["utente"] != "aziendale" + condizione = condizione1 & condizione2 + if not df[condizione].empty: + expndr = st.expander(f"Trovati errori nella descrizione tipo Kitas nel sheet {foglio}") + with expndr: + st.info("Errori riscontrati nella descrizione della tipologia Kitas") + make_grid(df[condizione].sort_values(by=["Cognome"])) + + # settiamo flag bool + df.loc[condizione, "errTipoKitas"] = True + #x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori tipologia Kitas", + # "errTipoKitas", + #) + return df + else: + return df + + +def errDataInizioFine(df, foglio): + condizione = df["DataInizio"] > df["DataFine"] + if not df[condizione].empty: + expndr = st.expander(f"Trovati errori data inizio maggiore di data fine nel sheet {foglio}") + with expndr: + st.info("Errori riscontrati; data inizio_maggiore data_fine") + make_grid(df[condizione].sort_values(by=["Cognome"])) + # settiamo flag bool + df.loc[condizione, "errDataInizioFine"] = True + #x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errDataInizioFine", + #) + return df + else: + return df + + +def errNome(df, foglio): + condizione1 = pd.isnull(df["Nome"]) + condizione2 = pd.isnull(df["Cognome"]) + condizione = condizione1 | condizione2 + if not df[condizione].empty: + expndr = st.expander(f"Trovati valori nulli per cognome o nome o entrambi nel sheet {foglio}") + with expndr: + st.info("Tabella con cognome o nome o entrambi assenti") + make_grid(df[condizione].sort_values(by=["Cognome"])) + # settiamo flag bool + df.loc[condizione, "errNome"] = True + #x = dwnld( + # df[condizione].sort_values(by=["Cognome"]), + # "Scaricare tabella con errori data inizio maggiore di data fine", + # "errNome", + # + return df + else: + return df + + +def get_data(uploaded_files): + df = {} + #dfout1 = None + #dfout2 = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + #df1 = pd.read_excel(uploaded_file, 0) # , usecols="A:F") + #df2 = pd.read_excel(uploaded_file, 1) + df['sheet0'] = df1 + df['sheet1'] = df2 + except ValueError as errore_Riscontrato: + st.error( + uploaded_file.name + + " non è un file Excel. Errore riscontrato: " + + str(errore_Riscontrato) + ) + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df,uploaded_file.name) + #df1 = prepare_data(df1, uploaded_file.name, 0) + #df2 = prepare_data(df2, uploaded_file.name, 1) + except ValueError as errore_Riscontrato: + st.error( + f"{str(uploaded_file.name)} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione. Errore: {str(errore_Riscontrato)}" + ) + continue + + # se dfout1 non esiste lo creiamo + if dfout1 is None: + dfout1 = pd.DataFrame(columns=df1.columns) + dfout1 = df1.copy() + del df1 + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout1 = pd.concat([dfout1, df1]) + del df1 + # se dfout2 non esiste lo creiamo + if dfout2 is None: + dfout2 = pd.DataFrame(columns=df2.columns) + dfout2 = df2 + del df2 + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout2 = pd.concat([dfout2, df2]) + del df2 + + # ora sono tutti concatenati e possiamo restituire il dataframe + + if not dfout1.empty and not dfout2.empty: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + return dfout1, dfout2 + + +def prepare_data(df, fn) #, foglio): + + + df['sheet0'] = df['sheet0'].drop(["Unnamed: 6", "Unnamed: 7"], axis=1) + df['sheet0'].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + ] + + df['sheet1'].columns = [ + "Cognome", + "Nome", + "utente", + "ComuneProvenienza", + "DataInizio", + "DataFine", + "delibera666", + "delibera543", + "delibera733", + "Entrate", + ] + + +# if foglio == 0: +# df = df.drop(["Unnamed: 6", "Unnamed: 7"], axis=1) +# df.columns = [ +# "Cognome", +# "Nome", +# "utente", +# "ComuneProvenienza", +# "DataInizio", +# "DataFine", +# ] +# elif foglio == 1: +# df.columns = [ +# "Cognome", +# "Nome", +# "utente", +# "ComuneProvenienza", +# "DataInizio", +# "DataFine", +# "delibera666", +# "delibera543", +# "delibera733", +# "Entrate", +# ] + + + df = make_bool_columns(df) + + + microstruttura = df.iloc[1] + microstruttura = microstruttura[1] + #st.write(f"microstruttura {microstruttura}") + res = isinstance(microstruttura, str) + if not res: + st.error(f"Manca informazione MICROSTRUTTURA nel foglio {foglio} nel file --> {fn}") + microstruttura = "assente" + # settiamo flag bool + df["dataErrMicrostruttura"] = True + ente = df.iloc[2] + ente = ente[1] + res = isinstance(ente, str) + if not res: + st.error(f"Manca informazione GESTORE nel foglio {foglio} nel file --> {fn}") + ente = 'assente' + df["dataErrGestore"] = True + df.insert(0, "Microstruttura", microstruttura) + df.insert(0, "Ente", ente) + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", fn) + df = df.drop(labels=range(0, 6), axis=0) + validi = df["Cognome"].notna() + df = df[validi] + + conditionInizio = pd.to_datetime(df["DataInizio"], errors="coerce").isnull() + conditionFine = pd.to_datetime(df["DataFine"], errors="coerce").isnull() + condition = conditionInizio | conditionFine + + if not df[condition].empty: + expndr = st.expander( + f"Trovati {len(df[condition])} errori formato data in foglio {foglio}" + ) + with expndr: + st.info("Errori nel formato della data inizio o data fine") + make_grid(df[condition].sort_values(by=["Cognome"])) + # settiamo la colonna bool + df.loc[condition, "errData"] = True + + # SOLUZIONE TEMPORANEA (?) + # se restituiamo con la data invalida crea problemi in seguito + df = df[~condition] + + return df + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def check_data2(df, checks, foglio): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + # global NO_ZERO + # NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df, foglio) + return df + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +def make_bool_columns(df): +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico + for a in (0,1): + + for e in ERRORDICT.keys(): + df['sheet'+str(a)][e] = np.nan + df['sheet'+str(a)][e] = df['sheet'+str(a)][e].astype("boolean") + + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + return df + + +app() diff --git a/pages/oldVersions/AutoReport.py b/pages/oldVersions/AutoReport.py new file mode 100644 index 0000000000000000000000000000000000000000..b24ebbd75ea92ceb4ea027c18ec96dc3ff40a0c5 --- /dev/null +++ b/pages/oldVersions/AutoReport.py @@ -0,0 +1,112 @@ +import pandas as pd +from fpdf import FPDF +from os import path +import streamlit as st + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errMassimo543": "Controllo valore massimo ore 543", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", +} + + +class PDF(FPDF): + def header(self): + # Logo + #self.image('head.jpg', 5, 1, 200) + self.ln(20) + def footer(self): + self.set_text_color(148,153,148) + #self.image('foot2.jpg', 5, 270, 200) + # Position at 1.5 cm from bottom + self.set_y(-15) + # Arial italic 8 + self.set_font('Arial', '', 8) + # Page number + self.cell(0, 10, 'Seite ' + str(self.page_no()) + '/{nb}', 0, 0, 'C') + + + + + + +def app(): + try: + df = pd.read_excel("storico.xlsx") + st.write(len(df)) + except: + st.write("file storico non trovato") + + for errore in ERRORDICT: + st.write(errore) + + pdf = PDF() + pdf.set_auto_page_break(auto=True, margin=20.0) + pdf.add_font( + "DejaVuSansCondensed-Oblique", + "", + "DejaVuSansCondensed-Oblique.ttf", + uni=True, + ) + pdf.add_page() + pdf.alias_nb_pages() + pdf.set_font("DejaVuSansCondensed-Oblique", "", 12) + pdf.cell( + 0, + 8, + "Risultati analisi file rendiconti TAGESMÜTTER ", + 0, + 1, + "C", + ) + + lista_enti = df["Ente"].unique() + #st.write(lista_enti) + for ente in lista_enti: + st.write(lista_enti) + pdf.cell(1,5,f"Risultati per {ente}",0,1) + pdf.ln(4) + df_errori = df[df["Ente"] == ente] + #for errore in ERRORDICT: + # if not df_errori[df_errori[errore] == True].empty: + # pdf.cell(1,5,f"Trovato un errore per {ERRORDICT[errore]}",0,1) + # st.write(df_errori[df_errori[errore] == True]) + + pdf.ln(4) + + pdf.output("testPDF.pdf", "F") + +app() \ No newline at end of file diff --git a/pages/oldVersions/autostatNew_bi.py b/pages/oldVersions/autostatNew_bi.py new file mode 100644 index 0000000000000000000000000000000000000000..2d7ff3eeb8ace5c9004ae7c354c9cfd6a2906435 --- /dev/null +++ b/pages/oldVersions/autostatNew_bi.py @@ -0,0 +1,419 @@ +import pandas as pd + +# import ipywidgets as widgets +from fpdf import FPDF +import sys + + +class PDF(FPDF): + def header(self): + # Logo + self.image("head.jpg", 5, 1, 200) + self.ln(20) + + def footer(self): + self.set_text_color(148, 153, 148) + # self.image('foot2.jpg', 5, 270, 200) + # Position at 1.5 cm from bottom + self.set_y(-15) + # Arial italic 8 + self.set_font("Arial", "", 8) + # Page number + self.cell(0, 10, "Seite " + str(self.page_no()) + "/{nb}", 0, 0, "C") + + +def makeBilingual(a): + if str(a) == "Ja": + a = "Ja/Sì" + if str(a) == "Sehr gut": + a = "Sehr gut/Molto bene" + if str(a) == "Gut": + a = "Gut/Bene" + if str(a) == "Ausreichend": + a = "Ausreichend/Sufficiente" + if str(a) == "Zum Teil": + a = "Zum Teil/In parte" + if str(a) == "Eher nicht": + a = "Eher nicht/Non molto" + if str(a) == "Nein": + a = "Nein/No" + if str(a) == "War nicht vorgesehen": + a = "War nicht vorgesehen/Non era previsto" + if str(a) == "Nicht ausreichend": + a = "Nicht ausreichend/Insufficiente" + if str(a) == "Sonstiges": + a = "Nein/nicht ausreichend - No/insufficiente" + return a + + +def cleanString(s): + s = s.replace("–", "-") + s = s.replace("„", '"') + s = s.replace("“", '"') + s = s.replace("…", "...") + s = s.replace("’", '"') + s = s.replace("”", '"') + s = s.replace("\n", "") + return s + + +def fixFileName(t): + t = cleanString(t) + fn = t + ".pdf" + fn = fn.replace("/", " ") + fn = fn.replace("\n", " ") + fn = fn.replace("'", "") + fn = fn.replace('"', "") + fn = fn.replace("&", " ") + fn = fn.replace("“", "") + fn = fn.replace("”", "") + fn = fn.replace("(in Rot Projekte ohne Gemeinde)", "") + # fn=fn.replace('“ETA BETA”','Eta Beta') + + print("\nFILE name is:", fn) + return fn + + +def writeTitle(t, df2): + pdf.ln(8) + pdf.set_font("Arial", "", 14) + pdf.ln() + pdf.cell( + 0, + 8, + "Zufriedenheitserhebung zur Ferien- bzw. Nachmittagsbetreuung 2021 - Ergebnisse", + 0, + 1, + "C", + ) + pdf.cell( + 0, + 10, + "Sondaggio di gradimento assistenza pomeridiana e durante le ferie 2021 - Risultati", + 0, + 1, + "C", + ) + pdf.ln(8) + pdf.set_font("Arial", "B", 11) + t = cleanString(t) + l = str(len(set(df2["Projekt"]))) + txt = ( + "Trägerkörperschaft/Ente gestore: " + + t.upper() + + "\nAnzahl Projekte/Numero progetti: " + + l + + ", ausgefüllte Fragebögen/questionari compilati: " + + str(len(df2)) + ) + txt = txt.replace("(IN ROT PROJEKTE OHNE GEMEINDE)", "") + pdf.multi_cell(0, 8, txt, 0, 1, "J") + + +def writeProjekt(p, z): + if p == "nan": + p = "NotFound" + try: + txt = ( + str(z) + + ") Projekt/Progetto: " + + p + + ", " + + str(len(df3)) + + " Fragebögen/Questionari" + ) + txt = cleanString(txt) + print("\t" + txt) + pdf.set_font("Arial", "B", 10) + pdf.ln(5) + pdf.multi_cell(180, 5, txt, 0, 1, "L") + except: + print(type(p), "p is ", p) + + +def getTraeger(t): + try: + df2 = df[df["Träger"] == t] + except: + print("error with ", t) + return df2 + + +def theKeys(): + lk = { + "Entsprechen Inhalte der Beschreibung?": "Inwiefern entsprechen die Inhalte des Kurses/Angebotes der Projektbeschreibung? - In che misura le attività proposte coincidevano con la descrizione del corso?", + "Wie war das Angebot organisiert?": "Wie war das Angebot organisiert? - Come valuta l'organizzazione del corso/progetto?", + "Hat Angebot Kind gefallen?": "Wie hat das Angebot Ihren Kind gefallen? - Quanto è piaciuta l'offerta a Suo/a figlio/a?", + "War Programm abwechslungsreich?": "War das Programm abwechslungsreich gestaltet? - Le attività proposte erano abbastanza varie?", + "Wie bewerten Sie Ort und Räumlichkeiten?": "Wie bewerten Sie Ort und Räumlichkeiten des Angebots? - Come valuta luogo e locali dell'offerta?", + "Ging Angebot auf Bedürfnisse Kindes ein?": "Ging das Angebot auf die Bedürfnisse Ihres Kindes ein? - Nell'offerta si è tenuto conto dei bisogni di vostro/a figlio/a?", + "Bestanden Bewegungsmöglichkeiten im Freien?": "Bestanden Bewegungsmöglichkeiten im Freien? - Si sono svolte attività di movimento all'aperto?", + "Wie bewerten Sie Kompetenz Betreuungspersonals?": "Wie bewerten Sie die Kompetenz des Betreuungspersonals? - Come valuta la competenza del personale educativo?", + "Wie bewerten Sie Qualität Verpflegung?": "Wie bewerten Sie die Qualität der gebotenen Verpflegung? - Come valuta la qualità del servizio mensa?", + "Bring- und Abholzeiten bedürfnisgerecht?": "Waren die Bring- und Abholzeiten bedürfnisgerecht? - I tempi di consegna e ritiro erano flessibili?", + "Wurden Informationen Vorfeld geliefert?": "Wurden alle wichtigen Informationen im Vorfeld geliefert? - Sono state fornite tutte le informazioni necessarie prima dell'iscrizione?", + "Teilnahmegebühren angemessen?": "Halten Sie die Teilnahmegebühren für angemessen? - Il costo Le sembra adeguato?", + "Kind noch einmal dieses/ähnliches Angebot?": "Würde sich Ihr Kind noch einmal für dieses oder ein ähnliches Angebot entscheiden? - Suo/a figlio/a sceglierebbe di nuovo questo corso/progetto o simili?", + } + return lk + + +def theKeys2(): + lk2 = { + "Eingeschrieben_Ansprechendes Programm": "Ansprechendes Programm - Programma interessante", + "Eingeschrieben_Kontakt zu Gleichaltrigen": "Kontakt zu Gleichaltrigen - Contatto con coetanei/e", + "Eingeschrieben_Berufstätigkeit der Eltern": "Berufstätigkeit der Eltern - Impegni lavorativi dei genitori", + "Eingeschrieben_Förderung der Entwicklung des Kindes": "Förderung der Entwicklung des Kindes - Promuovere lo sviluppo del/della bambino/a", + } + + lk3 = { + "GrundAngebot_Nähe Wohnort/Arbeitsplatz": "Nähe am Wohnort oder Arbeitsplatz - Vicinanza all" + "abitazione o al posto di lavoro", + "GrundAngebot_Von Bekannten empfohlen": "Von Bekannten empfohlen - Consigliato da amici/conoscenti (di mio/a figlio/a)", + "GrundAngebot_Gute Erfahrung": "Gute Erfahrung mit bisherigen Angeboten des Trägers - Buone esperienze con l'offerta del gestore", + "GrundAngebot_Zeitraum": "Zeitraum/Dauer des Kurses/Angebotes - Periodo e/o orario del corso/progetto", + "GrundAngebot_Preis-Leistungsverhältnis": "Preis-Leistungsverhältnis des Kurses/Angebotes - Rapporto qualità/costo del corso/progetto", + "GrundAngebot_Tätigkeiten/Programm": "Angebotene Tätigkeiten/Programm - Attività/programmi offerti", + } + return lk2, lk3 + + +def doTheKey(lk, df3, sowhat): + pdf.set_font("Arial", "", 10) + for k in lk: + llla = {} + pdf.ln(4) + pdf.multi_cell(0, 4, lk[k], 0, 1, "L") + pdf.ln(2) + df3 = df3[~df3[k].isnull()] # get rid of nan values + la = set(df3[k]) + for a in la: + llla[a] = makeBilingual(a) + llla = {llla[z]: z for z in llla} # invert keys and values + pdf.set_font("Arial", "I", 10) + for a in sorted( + llla, key=len + ): # in questo modo abbiamo Nein/Sonstiges alla fine della lista + try: + b = (df3[k].value_counts(normalize=True, dropna=False) * 100)[llla[a]] + except: + # print('k= ',k,'a= ',llla[a],'b: ',b) + sys.exit() + txt1 = "\t\t" + str(a) + txt2 = str(round(b, 1)) + "%" + pdf.ln(4) + pdf.cell(50, 0, txt1, 0, 0, "L") + pdf.cell(50, 0, txt2, 0, 1, "R") + + if sowhat != "niet": + if str(a) == "Nein/nicht ausreichend - No/insufficiente": + kk = k.replace("?", "") + kk = kk + "_Sonstiges" + bb = set(df3[kk]) + if len(bb) == 1: + pdf.set_font("Arial", "", 10) + pdf.ln(5) + pdf.cell(0, 0, "\t\tKeine Anmerkung/Nessuna annotazione", 0, 1) + continue + x = 0 + pdf.ln(5) + pdf.set_font("Arial", "", 10) + pdf.cell(0, 0, "\t\tAnmerkungen/Annotazioni:", 0, 1) + pdf.ln(3) + pdf.cell(5, 0, "", 0, 0) + + for i in bb: + if str(i) != "nan": + x = x + 1 + pdf.set_font("DejaVuSansCondensed-Oblique", "", 9) + pdf.multi_cell(165, 4, str(x) + ") " + str(i)) + pdf.ln(1) + pdf.cell(5, 0, "", 0, 0) + pdf.set_font("Arial", "I", 10) + pdf.ln(4) + pdf.set_font("Arial", "", 10) + + +def doTheKeys2(lk2, lk3, df3, sowhat): + pdf.set_font("Arial", "", 10) + tit = "Weshalb haben Sie Ihr Kind in einen Kurs/ein Angebot der Ferien- bzw. Nachmittagsbetreuung eingeschrieben?\nPerché ha scelto di iscrivere Suo/a figlio/a a un corso/progetto di assistenza pomeridiana e/o durante le ferie scolastiche?" + pdf.ln(6) + pdf.multi_cell(0, 4, tit, 0, 1, "L") + pdf.ln(2) + pdf.set_font("Arial", "I", 10) + for k in lk2: + txt = 0 + try: + txt = ( + str( + round( + (df3[k].value_counts(normalize=True, dropna=False) * 100)["Ja"], + 1, + ) + ) + + "%" + ) + except: + continue + + pdf.ln(4) + pdf.cell(127, 0, "\t\t" + lk2[k], 0, 0, "L") + pdf.cell(50, 0, txt, 0, 1, "R") + + pdf.ln(4) + txt = round( + ( + len(df3["Eingeschrieben_Sonstiges"].value_counts(normalize=True)) + / len(df3["Eingeschrieben_Sonstiges"]) + * 100 + ), + 1, + ) + txt = str(txt) + txt = txt + "%" + if sowhat != "niet": + if txt != "0.0%": + pdf.cell(127, 0, "\t\tSonstige Gründe/Altri motivi", 0, 0, "L") + pdf.cell(50, 0, txt, 0, 0, "R") + pdf.ln(4) + s = set(df3["Eingeschrieben_Sonstiges"]) + x = 0 + pdf.set_font("Arial", "", 10) + pdf.ln(1) + pdf.cell(60, 0, "\t\tAnmerkungen/Commenti:", 0, 1) + pdf.ln(3) + pdf.cell(5, 0, "", 0, 0) + for i in s: + if str(i) != "nan": + x = x + 1 + pdf.set_font("DejaVuSansCondensed-Oblique", "", 9) + pdf.multi_cell(165, 4, str(x) + ") " + str(i)) + pdf.ln(1) + pdf.cell(5, 0, "", 0, 0) + pdf.set_font("Arial", "", 10) + elif sowhat == "niet": + if txt != "0.0%": + pdf.cell(127, 0, "\t\tSonstige Gründe/Altri motivi", 0, 0, "L") + pdf.cell(50, 0, txt, 0, 0, "R") + pdf.ln(9) + + tit = "Aus welchem Grund haben Sie dieses spezifische Angebot gewählt?\nPer quale motivo ha scelto questa specifica offerta?" + pdf.set_font("Arial", "", 10) + pdf.ln(6) + pdf.multi_cell(0, 4, tit, 0, 1, "L") + pdf.ln(2) + pdf.set_font("Arial", "I", 10) + for k in lk3: + txt = 0 + try: + txt = ( + str( + round( + (df3[k].value_counts(normalize=True, dropna=False) * 100)["Ja"], + 1, + ) + ) + + "%" + ) + except: + continue + pdf.ln(4) + pdf.cell(127, 0, "\t\t" + lk3[k], 0, 0, "L") + pdf.cell(50, 0, txt, 0, 1, "R") + + +def doComments(df3): + n = 1 + pdf.ln(8) + if ( + len(set(df3["Anmerkungen/Verbesserungsvorschläge"])) < 2 + ): # non tutti lasciano un commento + return + pdf.set_font("Arial", "", 10) + tit = "Anmerkungen und Verbesserungsvorschläge - Osservazioni e suggerimenti" + tit = tit.upper() + pdf.ln(2) + pdf.cell(0, 0, tit, 0, 1, "L") + pdf.ln(2) + for a in set(df3["Anmerkungen/Verbesserungsvorschläge"]): + if str(a) != "nan": + pdf.ln(2) + txt = str(a) + txt = str(n) + ") " + txt + pdf.set_font("sysfont", "", 9.5) + pdf.multi_cell(0, 4, txt) # ,0,1,'L') + n = n + 1 + + +if __name__ == "__main__": + + df = pd.read_excel("../ExportVollständigNeuNoDemo.xlsx") + df = makeBilingual(df) + lt = set(df["Träger"]) + lg = set(df["Gemeinde"]) + print("we have", len(lt), "Träger") + print("we have", len(lg), "Gemeinden") + lk = theKeys() + lk2, lk3 = theKeys2() + x = 0 + y = 0 + for t in lt: + x = x + 1 + pdf = PDF() + pdf.set_auto_page_break(auto=True, margin=20.0) + pdf.add_font( + "DejaVuSansCondensed-Oblique", + "", + "DejaVuSansCondensed-Oblique.ttf", + uni=True, + ) + pdf.add_font("sysfont", "", r"c:\WINDOWS\Fonts\arial.ttf", uni=True) + pdf.add_page() + pdf.alias_nb_pages() + if t == "-->NotFound<--": + x = x - 1 + continue + if t != "KFS": # or t!= 'Gemeinde Lüsen': + continue + # if t != 'ASS. GIOV. “ETA BETA” JUGENDVEREIN ': + # continue + fn = fixFileName(t) + df2 = getTraeger(t) # riceviamo un df con solo il traeger in questione + writeTitle(t, df2) + lp = set(df2["Projekt"]) # lista dei progetti per il traeger in questione + z = 0 + for p in lp: + z = z + 1 + y = y + 1 + df3 = df2[df2["Projekt"] == p] + writeProjekt(p, z) + doTheKey(lk, df3, "yep") + doTheKeys2(lk2, lk3, df3, "yep") + doComments(df3) + pdf.add_page() + + pdf.set_font("Arial", "", 13) + pdf.ln() + pdf.cell( + 0, + 8, + "Zufriedenheitserhebung zur Ferien- bzw. Nachmittagsbetreuung 2021 - Ergebnisse Südtirol", + 0, + 1, + "C", + ) + pdf.cell( + 0, + 10, + "Sondaggio di gradimento assistenza pomeridiana e durante le ferie 2021 - Risultati Alto Adige", + 0, + 1, + "C", + ) + pdf.ln(8) + pdf.set_font("Arial", "", 10) + doTheKey(lk, df, "niet") + doTheKeys2(lk2, lk3, df, "niet") + pdf.output(fn, "F") + print("----> generated PDF files: ", x) + print("----> crunched projects: ", y) diff --git a/pages/oldVersions/tagesmutter27.py b/pages/oldVersions/tagesmutter27.py new file mode 100644 index 0000000000000000000000000000000000000000..7e7cf9866dae07e65e4aaa2087d51e732da7a0ed --- /dev/null +++ b/pages/oldVersions/tagesmutter27.py @@ -0,0 +1,1497 @@ +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errMassimo543": "Controllo valore massimo ore 543", + #"errOreRendicontateZero": "Controllo ore rendicontate uguali a zero" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +def errOreRendicontateZero(df): + pass + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + if not df[data_inizio_minima & data_inizio_massima & ore_543].empty: + expndr = st.expander("Trovato errore Eingewöhnung 543 Notbetreuung") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[data_inizio_minima & data_inizio_massima & ore_543]) + # settiamo la colonna bool + df.loc[ + (data_inizio_minima & data_inizio_massima & ore_543), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[data_inizio_minima & data_inizio_massima & ore_543], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + + if not df[inizio_minore_fine].empty: + expndr = st.expander("Trovato errore date contrattuali") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[inizio_minore_fine]) + # settiamo la colonna bool + df.loc[inizio_minore_fine, "errInizioMinoreFine"] = True + x = dwnld( + df[inizio_minore_fine], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + + if not df[codinvalido].empty: + expndr = st.expander("Trovato errore formato del codice fiscale") + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[codinvalido]) + # settiamo il flag bool per la tabella finale + df.loc[codinvalido, "errCodFisc1"] = True + x = dwnld( + df[codinvalido], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschhietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander("Trovato errore data nascita per codice fiscale") + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + if not df[ore_rendicontate_uguale_zero].empty: + expndr = st.expander("Trovato errore presenza") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[ore_rendicontate_uguale_zero]) + # settiamo la colonna bool + df.loc[ore_rendicontate_uguale_zero, "errErrorePresenza"] = True + x = dwnld( + df[ore_rendicontate_uguale_zero], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + # st.dataframe(giorni.values) + if not df[giorni].empty: + expndr = st.expander("Trovato errore età bambino (< 90 giorni)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[giorni]) + # settiamo la colonna bool + df.loc[ + giorni, + "errAgeChild", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + if not df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3].empty: + expndr = st.expander("Trovato errore dati 543") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3]) + df.loc[ + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3, + "errErroreDati543", + ] = True + x = dwnld( + df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + if not df[giorni].empty: + expndr = st.expander("Trovato errore fine contratto assistenza") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[giorni]) + + df.loc[ + giorni, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + if not df[data_nascita & data_fine_assistenza].empty: + expndr = st.expander("Trovato errore Kindergarten #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[data_nascita & data_fine_assistenza]) + df.loc[ + (data_nascita & data_fine_assistenza), + "errKindergarten_1", + ] = True + x = dwnld( + df[data_nascita & data_fine_assistenza], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime("01.01.2018", format="%d.%m.%Y") + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + if not df[data_nascita & data_nascita2 & data_fine_ass].empty: + expndr = st.expander("Trovato errore Kindergarten #2") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[data_nascita & data_nascita2 & data_fine_ass]) + df.loc[ + (data_nascita & data_nascita2 & data_fine_ass), + "errKindergarten_2", + ] = True + x = dwnld( + df[data_nascita & data_nascita2 & data_fine_ass], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_fine & ore_compensative].empty: + expndr = st.expander("Trovato errore finanziamento compensativo #2") + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[data_fine & ore_compensative]) + + df.loc[ + (data_fine & ore_compensative), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[data_fine & ore_compensative], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_inizio & ore_compensative].empty: + expndr = st.expander("Trovato errore finanziamento compensativo #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[data_inizio & ore_compensative]) + + df.loc[ + (data_inizio & ore_compensative), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[data_inizio & ore_compensative], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + if not df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate].empty: + expndr = st.expander("Trovato errore Eingewöhnung") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate] + ) + + df.loc[ + (data_inizio_minima & data_inizio_massima & ore_contrattualizzate), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + if not df[data_inizio_minima & data_inizio_massima & ore_543].empty: + expndr = st.expander("Trovato errore Eingewöhnung 543 Lockdown") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[data_inizio_minima & data_inizio_massima & ore_543]) + + df.loc[ + (data_inizio_minima & data_inizio_massima & ore_543), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[data_inizio_minima & data_inizio_massima & ore_543], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)].empty: + expndr = st.expander("Trovato errore Covid #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)] + ) + + df.loc[ + (data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)), + "errErroreCovid", + ] = True + x = dwnld( + df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander("Trovato errore Covid #2") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + if not df[data_inizio & data_fine & ore_543].empty: + expndr = st.expander("Trovato errore Covid #3") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[data_inizio & data_fine & ore_543]) + + df.loc[ + data_inizio & data_fine & ore_543, + "errErroreCovid3", + ] = True + x = dwnld( + df[data_inizio & data_fine & ore_543], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + + if not df[condizione1 & condizione2].empty: + expndr = st.expander("Trovato contratti lockdown da controllare (Covid #4)") + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione1 & condizione2]) + + df.loc[ + condizione1 & condizione2, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione1 & condizione2], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + "Ore totali rendicontate per il 2020" + ] + + conta_cod_fiscale = ( + df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + ) + + # presenza errore in caso di codfisc che occorre solo una volta + df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + if not df[condizioneerrore2].empty: + expndr = st.expander( + "Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizioneerrore2]) + + # settiamo il flag bool per la tabella finale + df.loc[condizioneerrore2, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizioneerrore2], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + if not df[condizionelogica2].empty: + expndr = st.expander("Trovato errore ore complessive maggiore di 1920") + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizionelogica2]) + + # settiamo flag per tabella finale + df.loc[condizionelogica2, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizionelogica2], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + + if not df[condizionlogica].empty: + expndr = st.expander("Trovati bambini presenti in più comuni") + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizionlogica]) + + # settiamo flag bool per tabella finale + df.loc[condizionlogica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizionlogica], + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + + if not df[condizione].empty: + expndr = st.expander("Trovati bambini con annotazioni") + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione]) + + # settiamo flag bool + df.loc[condizione, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione], + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "eppan" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bozen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "branzoll" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "freienfeld" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "auer" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "leifers" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "mals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "welschnofen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "ratschings" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "pfatten" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "feldthurns" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "sterzing" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bolzano" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bronzolo" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "trens" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "egna" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "laives" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "malles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nalles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "levante" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "racines" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vadena" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "velturno" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vipiteno" + ) + ) + + if not df[cond1 & cond1b].empty: + df.loc[cond1 & cond1b,"gg1"] = 74 + else: + df[cond1 & cond1b,"gg1"] = 0 + + if not df[cond2 & cond2b].empty: + df.loc[cond2 & cond2b,"gg2"] = 8 + else: + df.loc[cond2 & cond2b,"gg2"] = 0 + + if not df[cond3 & cond3b & cond3c].empty: + df.loc[cond3 & cond3b & cond3c, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + df = df.drop(["gg1", "gg2", "gg3"], axis=1) # non servono più + + if not df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)].empty: + expndr = st.expander("Calcolata colonna massimo ore 543") + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c), + "errMassimo543", + ] = True + x = dwnld( + df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +# fine checks + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols = "A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + # df = df.drop( + # df.columns[ + # [ + # 16, + # 17, + # 18, + # 19, + # 20, + # 21, + # 22, + # 23, + # 24, + # 25, + # 26, + # 27, + # 28, + # 29, + # 30, + # 31, + # 32, + # 33, + # 34, + # 35, + # 36, + # 37, + # 38, + # ] + # ], + # axis=1, + # ) + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + dffinal = dffinal[condizione] + + return dffinal + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.27)") + dfout = None + + # carichiamo qui la tabella dello storico?? + if path.exists("storico.xlsx"): + c1, c2 = st.columns(2) + c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + +app() diff --git a/pages/oldVersions/tagesmutter28.py b/pages/oldVersions/tagesmutter28.py new file mode 100644 index 0000000000000000000000000000000000000000..9512b141c70ab660f05b3c629337a810fadd64c9 --- /dev/null +++ b/pages/oldVersions/tagesmutter28.py @@ -0,0 +1,1521 @@ +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + +#CONDIZIONE_NO_ORE_RENDICONTATE_ZERO = df["errOreRendicontateZero"] != 0 + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errMassimo543": "Controllo valore massimo ore 543", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + + +def errOreRendicontateZero(df): + condizione = df['Ore totali rendicontate per il 2020'] == 0 + + if not df[condizione].empty: + expndr = st.expander("Trovati bambini con ore totali rendicontate = 0") + with expndr: + st.info("Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020") + make_grid(df[condizione]) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 + + if not df[condizione_logica].empty: + expndr = st.expander("Trovato errore Eingewöhnung 543 Notbetreuung") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + + if not df[inizio_minore_fine].empty: + expndr = st.expander("Trovato errore date contrattuali") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[inizio_minore_fine]) + # settiamo la colonna bool + df.loc[inizio_minore_fine, "errInizioMinoreFine"] = True + x = dwnld( + df[inizio_minore_fine], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + + if not df[codinvalido].empty: + expndr = st.expander("Trovato errore formato del codice fiscale") + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[codinvalido]) + # settiamo il flag bool per la tabella finale + df.loc[codinvalido, "errCodFisc1"] = True + x = dwnld( + df[codinvalido], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschhietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander("Trovato errore data nascita per codice fiscale") + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + if not df[ore_rendicontate_uguale_zero].empty: + expndr = st.expander("Trovato errore presenza") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[ore_rendicontate_uguale_zero]) + # settiamo la colonna bool + df.loc[ore_rendicontate_uguale_zero, "errErrorePresenza"] = True + x = dwnld( + df[ore_rendicontate_uguale_zero], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + # st.dataframe(giorni.values) + if not df[giorni].empty: + expndr = st.expander("Trovato errore età bambino (< 90 giorni)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[giorni]) + # settiamo la colonna bool + df.loc[ + giorni, + "errAgeChild", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + if not df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3].empty: + expndr = st.expander("Trovato errore dati 543") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3]) + df.loc[ + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3, + "errErroreDati543", + ] = True + x = dwnld( + df[errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + if not df[giorni].empty: + expndr = st.expander("Trovato errore fine contratto assistenza") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[giorni]) + + df.loc[ + giorni, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + if not df[data_nascita & data_fine_assistenza].empty: + expndr = st.expander("Trovato errore Kindergarten #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[data_nascita & data_fine_assistenza]) + df.loc[ + (data_nascita & data_fine_assistenza), + "errKindergarten_1", + ] = True + x = dwnld( + df[data_nascita & data_fine_assistenza], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime("01.01.2018", format="%d.%m.%Y") + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + if not df[data_nascita & data_nascita2 & data_fine_ass].empty: + expndr = st.expander("Trovato errore Kindergarten #2") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[data_nascita & data_nascita2 & data_fine_ass]) + df.loc[ + (data_nascita & data_nascita2 & data_fine_ass), + "errKindergarten_2", + ] = True + x = dwnld( + df[data_nascita & data_nascita2 & data_fine_ass], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_fine & ore_compensative].empty: + expndr = st.expander("Trovato errore finanziamento compensativo #2") + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[data_fine & ore_compensative]) + + df.loc[ + (data_fine & ore_compensative), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[data_fine & ore_compensative], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_inizio & ore_compensative].empty: + expndr = st.expander("Trovato errore finanziamento compensativo #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[data_inizio & ore_compensative]) + + df.loc[ + (data_inizio & ore_compensative), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[data_inizio & ore_compensative], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + if not df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate].empty: + expndr = st.expander("Trovato errore Eingewöhnung") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate] + ) + + df.loc[ + (data_inizio_minima & data_inizio_massima & ore_contrattualizzate), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[data_inizio_minima & data_inizio_massima & ore_contrattualizzate], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + if not df[data_inizio_minima & data_inizio_massima & ore_543].empty: + expndr = st.expander("Trovato errore Eingewöhnung 543 Lockdown") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[data_inizio_minima & data_inizio_massima & ore_543]) + + df.loc[ + (data_inizio_minima & data_inizio_massima & ore_543), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[data_inizio_minima & data_inizio_massima & ore_543], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + if not df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)].empty: + expndr = st.expander("Trovato errore Covid #1") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)] + ) + + df.loc[ + (data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)), + "errErroreCovid", + ] = True + x = dwnld( + df[data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate)], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander("Trovato errore Covid #2") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + if not df[data_inizio & data_fine & ore_543].empty: + expndr = st.expander("Trovato errore Covid #3") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[data_inizio & data_fine & ore_543]) + + df.loc[ + data_inizio & data_fine & ore_543, + "errErroreCovid3", + ] = True + x = dwnld( + df[data_inizio & data_fine & ore_543], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + + if not df[condizione1 & condizione2].empty: + expndr = st.expander("Trovato contratti lockdown da controllare (Covid #4)") + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione1 & condizione2]) + + df.loc[ + condizione1 & condizione2, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione1 & condizione2], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + "Ore totali rendicontate per il 2020" + ] + + conta_cod_fiscale = ( + df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + ) + + # presenza errore in caso di codfisc che occorre solo una volta + df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + if not df[condizioneerrore2].empty: + expndr = st.expander( + "Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizioneerrore2]) + + # settiamo il flag bool per la tabella finale + df.loc[condizioneerrore2, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizioneerrore2], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + if not df[condizionelogica2].empty: + expndr = st.expander("Trovato errore ore complessive maggiore di 1920") + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizionelogica2]) + + # settiamo flag per tabella finale + df.loc[condizionelogica2, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizionelogica2], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + + if not df[condizionlogica].empty: + expndr = st.expander("Trovati bambini presenti in più comuni") + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizionlogica]) + + # settiamo flag bool per tabella finale + df.loc[condizionlogica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizionlogica], + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + + if not df[condizione].empty: + expndr = st.expander("Trovati bambini con annotazioni") + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione]) + + # settiamo flag bool + df.loc[condizione, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione], + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "eppan" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bozen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "branzoll" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "freienfeld" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "auer" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "leifers" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "mals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "welschnofen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "ratschings" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "pfatten" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "feldthurns" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "sterzing" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bolzano" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bronzolo" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "trens" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "egna" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "laives" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "malles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nalles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "levante" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "racines" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vadena" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "velturno" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vipiteno" + ) + ) + + if not df[cond1 & cond1b].empty: + df.loc[cond1 & cond1b,"gg1"] = 74 + else: + df[cond1 & cond1b,"gg1"] = 0 + + if not df[cond2 & cond2b].empty: + df.loc[cond2 & cond2b,"gg2"] = 8 + else: + df.loc[cond2 & cond2b,"gg2"] = 0 + + if not df[cond3 & cond3b & cond3c].empty: + df.loc[cond3 & cond3b & cond3c, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + + + if not df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)].empty: + expndr = st.expander("Calcolata colonna massimo ore 543") + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c), + "errMassimo543", + ] = True + x = dwnld( + df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +# fine checks + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols = "A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + # df = df.drop( + # df.columns[ + # [ + # 16, + # 17, + # 18, + # 19, + # 20, + # 21, + # 22, + # 23, + # 24, + # 25, + # 26, + # 27, + # 28, + # 29, + # 30, + # 31, + # 32, + # 33, + # 34, + # 35, + # 36, + # 37, + # 38, + # ] + # ], + # axis=1, + # ) + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + df = df.drop(["gg1", "gg2", "gg3"], axis=1) # servivano per calcolare ore massime 543 + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + dffinal = dffinal[condizione] + + return dffinal + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.28)") + dfout = None + + # carichiamo qui la tabella dello storico?? + if path.exists("storico.xlsx"): + c1, c2 = st.columns(2) + c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + +app() diff --git a/pages/oldVersions/tagesmutter29.py b/pages/oldVersions/tagesmutter29.py new file mode 100644 index 0000000000000000000000000000000000000000..54d230b0844b5db96e741d261688835042b11922 --- /dev/null +++ b/pages/oldVersions/tagesmutter29.py @@ -0,0 +1,1532 @@ +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errMassimo543": "Controllo valore massimo ore 543", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + + +def errOreRendicontateZero(df): + condizione = df['Ore totali rendicontate per il 2020'] == 0 + + if not df[condizione].empty: + expndr = st.expander(f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)") + with expndr: + st.info(f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020") + make_grid(df[condizione]) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + #NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica]) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander(f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore presenza ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica]) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime("01.01.2018", format="%d.%m.%Y") + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[condizione_logica] + ) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid( + df[condizione_logica] + ) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander(f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + #condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + #] + + #conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + #) + #condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + #df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica]) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica]) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)") + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica]) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander(f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)") + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica]) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "eppan" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bozen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "branzoll" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "freienfeld" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "auer" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "leifers" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "mals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nals" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "welschnofen" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "ratschings" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "pfatten" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "feldthurns" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "sterzing" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bolzano" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "bronzolo" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "trens" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "egna" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "laives" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "malles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "nalles" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "levante" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "racines" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vadena" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "velturno" + ) + | df["Comune di residenza assistente domiciliare all'infanzia"].str.lower().str.contains( + "vipiteno" + ) + ) + + + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO,"gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO,"gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO,"gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO,"gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + + + if not df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)].empty: + expndr = st.expander(f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} errori)") + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +# fine checks + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols = "A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + df = df.drop(["gg1", "gg2", "gg3"], axis=1) # servivano per calcolare ore massime 543 + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + dffinal = dffinal.drop(["errMassimo543"], axis = 1) + + return dffinal + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.29)") + dfout = None + + # carichiamo qui la tabella dello storico?? + if path.exists("storico.xlsx"): + c1, c2 = st.columns(2) + c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + +app() diff --git a/pages/oldVersions/tagesmutter30.py b/pages/oldVersions/tagesmutter30.py new file mode 100644 index 0000000000000000000000000000000000000000..b4d66ece884861c001466d682d0e3739fdd5de22 --- /dev/null +++ b/pages/oldVersions/tagesmutter30.py @@ -0,0 +1,1656 @@ +from curses import ERR +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Controllo valore massimo ore 543", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione]) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + # NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica]) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica]) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica]) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica]) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica]) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica]) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + # st.write(f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}") + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + # elenco_bambini = df["Cognome e nome bambino"][condizione].unique() + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + row += 1 + row += 1 + + workbook.close() + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.30)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter31.py b/pages/oldVersions/tagesmutter31.py new file mode 100644 index 0000000000000000000000000000000000000000..59c7f1b654976b4a6ac6a5aed19ec7b98ac11cd5 --- /dev/null +++ b/pages/oldVersions/tagesmutter31.py @@ -0,0 +1,1674 @@ +from curses import ERR +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Controllo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + #st.write(df_somme) + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + return df + else: + return df + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione]) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + # NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica]) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica]) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica]) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica]) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica]) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica]) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + # st.write(f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}") + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + # elenco_bambini = df["Cognome e nome bambino"][condizione].unique() + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + row += 1 + row += 1 + + workbook.close() + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.31)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter32.py b/pages/oldVersions/tagesmutter32.py new file mode 100644 index 0000000000000000000000000000000000000000..8e43768cac3f148cc0d3e3a29c599bc4937977b9 --- /dev/null +++ b/pages/oldVersions/tagesmutter32.py @@ -0,0 +1,1678 @@ +from curses import ERR +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Controllo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + #"errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + #st.write(df_somme) + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + return df + else: + return df + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione]) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione], + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + # NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica], + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica]) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica]) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica]) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni], + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica]) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ] + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ], + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica]) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica]) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica]) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica], + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ] + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ], + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + # st.write(f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}") + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + # elenco_bambini = df["Cognome e nome bambino"][condizione].unique() + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + row += 1 + row += 1 + + workbook.close() + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.32)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter33.py b/pages/oldVersions/tagesmutter33.py new file mode 100644 index 0000000000000000000000000000000000000000..26c87673a7d159c71bfec894b4a6c51dcd5a975f --- /dev/null +++ b/pages/oldVersions/tagesmutter33.py @@ -0,0 +1,1677 @@ +from curses import ERR +from os import path +from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Controllo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + return df + else: + return df + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=['Cognome e nome bambino'])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=['Cognome e nome bambino']), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + # NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=['Cognome e nome bambino'])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=['Cognome e nome bambino']) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=['Cognome e nome bambino'])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=['Cognome e nome bambino']) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=['Cognome e nome bambino']), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + # st.write(f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}") + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + # elenco_bambini = df["Cognome e nome bambino"][condizione].unique() + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + row += 1 + row += 1 + + workbook.close() + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.33)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinal) + AgGrid(dffinal, gridOptions=gridOptions, enable_enterprise_modules=True) + dwnld(dffinal, "SCARICARE TABELLA CON TUTTI I DATI", "tuttidati") + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid(dffinalerr) + AgGrid( + dffinalerr, gridOptions=gridOptions, enable_enterprise_modules=True + ) + dwnld(dffinalerr, "SCARICARE TABELLA CON SOLO ERRORI", "soloerrori") + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter34.py b/pages/oldVersions/tagesmutter34.py new file mode 100644 index 0000000000000000000000000000000000000000..767b10fd8a3432db0caec6baa9deec1831726f86 --- /dev/null +++ b/pages/oldVersions/tagesmutter34.py @@ -0,0 +1,1714 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(dff): + dff.to_csv("test2.csv", encoding="utf-8-sig") + df = pd.read_csv("test2.csv") + + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + # elenco_bambini = df["Cognome e nome bambino"][condizione].unique() + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx") + file = ddff.to_csv(sep=';').encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.34)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter35.py b/pages/oldVersions/tagesmutter35.py new file mode 100644 index 0000000000000000000000000000000000000000..defd2642cf171b559ca033b3a3890728b3e4ac8d --- /dev/null +++ b/pages/oldVersions/tagesmutter35.py @@ -0,0 +1,1715 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + #dff.to_csv("test2.csv", encoding="utf-8-sig") + #df = pd.read_csv("test2.csv") + + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + #worksheet.set_column('A:A',0) + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + df_bambini.sort_values(by="Cognome e nome bambino", ascending=True, inplace=True) + for i, r in df_bambini.iterrows(): + # st.write(r["Cognome e nome bambino"]) + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx",index_col = False) + ddff.reset_index(drop=True, inplace = True) + file = ddff.to_csv(sep=';').encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.35)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter36.py b/pages/oldVersions/tagesmutter36.py new file mode 100644 index 0000000000000000000000000000000000000000..7fc688f71e826f2b0476cb1bee7eee9c170f2293 --- /dev/null +++ b/pages/oldVersions/tagesmutter36.py @@ -0,0 +1,1728 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Calcolo delle somme ore per comune" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + +def errCalcoloSomme(df): + df_somme = df.groupby("Comune",as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE PER COMUNE", + "errCalcoloSomme", + ) + + return df + else: + return df + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SCELTA CONTROLLI", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values(by="Cognome e nome bambino", ascending=True)#, inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx",index_col = False) + ddff.reset_index(drop=True, inplace = True) + file = ddff.to_csv(sep=';').encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.36)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter37.py b/pages/oldVersions/tagesmutter37.py new file mode 100644 index 0000000000000000000000000000000000000000..feddd2a5ce500496aeb8e0a5c7f736bee560187f --- /dev/null +++ b/pages/oldVersions/tagesmutter37.py @@ -0,0 +1,1758 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Calcolo delle somme ore per comune", + "errCalcoloNumeroBimbi": "Calcolo numero bambini per comune e tipo ore" +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +##################### START CHECKS + +def errCalcoloNumeroBimbi(df): + df1 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020'].apply(lambda x: x[x > 0].count()) + df2 = df.groupby('Comune',as_index=False)['Ore di assistenza \n ai sensi della delibera\nn. 666/2019'].apply(lambda x: x[x > 0].count()) + df3 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020'].apply(lambda x: x[x > 0].count()) + df4 = df.groupby('Comune',as_index=False)['Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)'].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1,df2, on = 'Comune', how = 'outer') + dfx = pd.merge(dfx,df3, on = 'Comune', how = 'outer') + dfx = pd.merge(dfx,df4, on = 'Comune', how = 'outer') + + dfx.columns = ["Comune", "Nr. bimbi ore 543", "Nr. bimbi ore 666", "Nr. bimbi ore 733", "Nr. bimbi finanziamento compensativo"] + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + gridOptions = buildGrid(dfx) + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + dfx, + "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + "soloerrori", + ) + + return df + + + + + +def errCalcoloSomme(df): + df_somme = df.groupby("Comune",as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE PER COMUNE", + "errCalcoloSomme", + ) + + return df + else: + return df + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + condizione_logica = condizionlogica1 # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + return df + + +##################### FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values(by="Cognome e nome bambino", ascending=True)#, inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx",index_col = False) + ddff.reset_index(drop=True, inplace = True) + file = ddff.to_csv(sep=';').encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 0.9.37)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/oldVersions/tagesmutter38.py b/pages/oldVersions/tagesmutter38.py new file mode 100644 index 0000000000000000000000000000000000000000..4880ff578ee1cab5a3536938f0a06e719da350a6 --- /dev/null +++ b/pages/oldVersions/tagesmutter38.py @@ -0,0 +1,1828 @@ +# from curses import ERR +from os import path + +# from unicodedata import name + +import numpy as np +import pandas as pd +import xlsxwriter +import streamlit as st +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from this import d + +st.set_page_config( + page_title="Controllo Errori TAGESMÜTTER", layout="wide", page_icon="😃" # 👽 +) + +DATAINIZIOMINIMA = pd.to_datetime("18.05.2020", format="%d.%m.%Y") +DATAFINEMASSIMA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +DATAFINEMASSIMA_COVID4 = pd.to_datetime("17.05.2020", format="%d.%m.%Y") + +ORE2020 = 1920 +KONTROLLEKINDERGARTEN_DATANASCITA_1 = pd.to_datetime("28.02.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +KONTROLLEKINDERGARTEN_DATANASCITA_2 = pd.to_datetime("01.03.2017", format="%d.%m.%Y") +KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_2 = pd.to_datetime( + "15.09.2019", format="%d.%m.%Y" +) +EINGEWÖHNUNG_DATAINIZIO_MIN = pd.to_datetime("13.02.2020", format="%d.%m.%Y") +EINGEWÖHNUNG_DATAINIZIO_MAX = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAINIZIOASSISTENZA = pd.to_datetime("05.03.2020", format="%d.%m.%Y") +KONTROLLECOVID_DATAFINEASSISTENZA2 = pd.to_datetime("30.10.2020", format="%d.%m.%Y") +KONTROLLECOVID2_DATAINIZIOASSISTENZA = pd.to_datetime("24.11.2020", format="%d.%m.%Y") +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN = pd.to_datetime( + "26.10.2020", format="%d.%m.%Y" +) +KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX = pd.to_datetime( + "16.11.2020", format="%d.%m.%Y" +) + + +# riferimento centrale e unico per la gestione dei controlli +ERRORDICT = { + # gestiamo tutto quello che riguarda i controlli da fare qui + # in seguito usiamo la key del dict per creare sia le checkbox + # sia per chiamare le funzioni, sia per creare la colonna bool + # per la tabella con soli errori + # + # in sostanza: vogliamo che ERRORDICT sia il riferimento unico + # per tutti i controlli che facciamo + # + # basta aggiungere qui un nuovo errore e la descrizione + # e i checkbox etc vengono creati automaticamente + "errCodFisc1": "Controllo formato codice fiscale", + "errCodFisc2": "Controllo data nascita per codice fiscale", + "errAgeChild": "Controllo età bambino", + "errInizioMinoreFine": "Controllo date contrattuali", + "errErrorePresenza": "Controllo errore presenza", + "errErroreDati543": "Controllo errore dati 543", + "errFineAssistenzaMax4Anni": "Controllo fine contratto assistenza", + "errKindergarten_1": "Controllo Kindergarten #1", + "errKindergarten_2": "Controllo Kindergarten #2", + "errErroreFinanziamentoCompensativo": "Controllo finanziamento compensativo", + "errErroreFinanziamentoCompensativo2": "Controllo finanziamento compensativo #2", + "errErroreCovid": "Controllo Covid #1", + "errErroreCovid2": "Controllo Covid #2", + "errErroreCovid3": "Controllo Covid #3", + "errErroreCovid4": "Contratti lockdown sospetti (Covid #4)", + "errFehlerEingewöhnung": "Controllo Fehler Eingewöhnung", + "errFehlerEingewöhnung543Lockdown": "Controllo Fehler Eingewöhnung 543 Lockdown", + "errFehlerEingewöhnung543Notbetreuung": "Controllo Fehler Eingewöhnung 543 Notbetreuung", + "errGesamtstundenVertragszeitraum": "Controllo ore complessive periodo contrattuale", + "errSuperatoOreMassime1920": "Controllo ore complessive superiore a 1920", + "errBambinoInPiuComuni": "Bambino presente in più comuni", + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Controllo ore rendicontate uguali a zero", + "errMassimo543": "Calcolo valore massimo ore 543", + "errSommaOre": "Calcolo somme per le ore riportate", + "errMassimoFC": "Calcolo valore massimo ore finanziamento compensativo", + "errCalcoloSomme": "Calcolo delle somme ore per comune", + "errCalcoloNumeroBimbi": "Calcolo numero bambini per comune e tipo ore", +} + + +def buildGrid(data): + gb = GridOptionsBuilder.from_dataframe(data) + # gb.configure_pagination() + gb.configure_side_bar() + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + gb.configure_default_column( + groupable=True, value=True, enableRowGroup=True, aggFunc="count", editable=True + ) + gridOptions = gb.build() + return gridOptions + + +# aggiungiamo le colonne bool per ogni errore che abbiamo definito in ERRORDICT +# ci serve per creare la tabella finale e per avere uno storico +def make_bool_columns(df): + for e in ERRORDICT.keys(): + df[e] = np.nan + df[e] = df[e].astype("boolean") + + return df + + +# lancia i singoli controlli in base alla selezione fatta in GUI +def check_data2(df, checks): + # definiamo come variabile globale la condizione logica per evitare i record con + # ore rendicontate 2020 = 0 + global NO_ZERO + NO_ZERO = df["Ore totali rendicontate per il 2020"] > 0 + for e in checks.keys(): + # per ogni errore vediamo se è stato scelto come checkbox + # se è true, eseguiamo... + if checks[e]: + # il nome della funzione da chiamare è contenuta nel dict + # ed è lo stesso nome dell'errore + funzione = globals()[e] + # abbiamo creato il nome della funzione da chiamare e salvato in "funzione" + # in questo modo vengono chiamate tutte le funzioni che hanno la + # checkbox == True + df = funzione(df) + return df + + +################################## +# START CHECKS + + +def errCalcoloNumeroBimbi(df): + df1 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ].apply(lambda x: x[x > 0].count()) + df2 = df.groupby("Comune", as_index=False)[ + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019" + ].apply(lambda x: x[x > 0].count()) + df3 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020" + ].apply(lambda x: x[x > 0].count()) + df4 = df.groupby("Comune", as_index=False)[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ].apply(lambda x: x[x > 0].count()) + dfx = pd.merge(df1, df2, on="Comune", how="outer") # outer join + dfx = pd.merge(dfx, df3, on="Comune", how="outer") + dfx = pd.merge(dfx, df4, on="Comune", how="outer") + + dfx.columns = [ + "Comune", + "Nr. bimbi ore 543", + "Nr. bimbi ore 666", + "Nr. bimbi ore 733", + "Nr. bimbi finanziamento compensativo", + ] + + expndr = st.expander("Tabella conteggio bimbi per comune e tipologia ore") + with expndr: + st.info("Conteggio dei bambini per tipologia di ora e per comune") + gridOptions = buildGrid(dfx) + AgGrid(dfx, gridOptions=gridOptions, enable_enterprise_modules=True) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + dfx, + "SCARICARE TABELLA CON CONTEGGIO NUMERO BIMBI PER COMUNE E TIPO ORE", + "soloerrori", + ) + + return df + + +def errCalcoloSomme(df): + df_somme = df.groupby("Comune", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con somme ore per comune") + with expndr: + st.info("Valori sommati ore per comune") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE PER COMUNE", + "errCalcoloSomme", + ) + + return df + else: + return df + + +def errSommaOre(df): + df_somme = df.groupby("Ente", as_index=False).sum() + if not df_somme.empty: + expndr = st.expander("Tabella con calcolo delle somme") + with expndr: + st.info("Valori sommati") + make_grid(df_somme) + # non settiamo il flag bool perché qui non ci serve + x = dwnld( + df_somme, + "SCARICARE TABELLA CON SOMME DELLE ORE", + "errSommaOre", + ) + + return df + else: + return df + + +def errOreRendicontateZero(df): + condizione = df["Ore totali rendicontate per il 2020"] == 0 + + if not df[condizione].empty: + expndr = st.expander( + f"Trovati bambini con ore totali rendicontate = 0 ({len(df[condizione])} errori)" + ) + with expndr: + st.info( + f"Elenco dei bambini che hanno un valore di zero nelle ore rendicontate per l'anno 2020" + ) + make_grid(df[condizione].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione, "errOreRendicontateZero"] = True + x = dwnld( + df[condizione].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON VALORE ZERO PER ORE RENDICONTATE 2020", + "errOreRendicontateZero", + ) + return df + else: + return df + + +def errFehlerEingewöhnung543Notbetreuung(df): + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= KONTROLLEEINGEWÖHNUNG543NOTBETREUUNG_DATAINIZIOMAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Notbetreuung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio >= 26.10.2020 e dataInizio <= 16.11.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Notbetreuung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI Fehler Eingewöhnung 543 Notbetreuung", + "FehlerEingewoehnung543Notbetreuung", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errInizioMinoreFine(df): + + inizio_minore_fine = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + condizione_logica = inizio_minore_fine & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore date contrattuali ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato un errore secondo la condizione: (dataInizio > dataFine)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errInizioMinoreFine"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON ERRORI data Inizio maggiore data fine", + "FehlerInzioMinoreFine", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc1(df): + # definiamo condizione logica trovare per codice fiscale invalido usando regex + codinvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == False + ) + condizione_logica = codinvalido & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore formato del codice fiscale ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno un codice fiscale nel formato non corretto" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errCodFisc1"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore codice fiscale", + "ErroreCodiceFiscale", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errCodFisc2(df): + # condizione logica via regex per usare solo records con codfisc nel formato corretto + codvalido = ( + df["Codice fiscale"].str.match( + "[A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z][A-Z|a-z]\d\d[A-Z|a-z]\d\d[A-Z|a-z]\d\d\d[A-Z|a-z]" + ) + == True + ) + # potremmo fare a meno di usare un nuovo df?? + # è più semplice se usiamo un nuovo df + dfcod = df[codvalido] + + # condizione logica per i maschietti + ggnot40 = dfcod["Codice fiscale"].str[9:11].astype(int) < 40 + + # condizione logica per e femmine, che hanno giorno nascita da 40 in poi + g40 = dfcod["Codice fiscale"].str[9:11].astype(int) > 40 + + # nuovi df per maschietti e femmine + df40 = dfcod[g40] + dfnot40 = dfcod[ggnot40] + + # condizione logica verifica giorno nascita femmine + gg40 = ( + pd.to_datetime(df40["Data di nascita"]).dt.day + == df40["Codice fiscale"].str[9:11].astype(int) - 40 + ) + # condizione logica verifica giorno nascita maschietti + gg = pd.to_datetime(dfnot40["Data di nascita"]).dt.day == dfnot40[ + "Codice fiscale" + ].str[9:11].astype(int) + + # condizione logica per ANNO NASCITA uguale anno codfisc + anno = dfcod["Data di nascita"].dt.year == 2000 + dfcod["Codice fiscale"].str[ + 6:8 + ].astype(int) + + # condizione logica per MESE NASCITA + mese = dfcod["Data di nascita"].dt.month == dfcod["Codice fiscale"].str[8:9].astype( + "str" + ).replace( + { + "A": "1", + "B": "2", + "C": "3", + "D": "4", + "E": "5", + "H": "6", + "L": "7", + "M": "8", + "P": "9", + "R": "10", + "S": "11", + "T": "12", + "F": "99", + "G": "99", + "I": "99", + "J": "99", + "K": "99", + "N": "99", + "O": "99", + "Q": "99", + "U": "99", + "V": "99", + "W": "99", + "X": "99", + "Y": "99", + "Z": "99", + } + ).astype( + int + ) + + # se trovato errore maschietti o femmine o mese o anno per maschi/femmine + if ( + not dfcod[~mese].empty + or not dfnot40[~gg].empty + or not df40[~gg40].empty + or not dfcod[~anno].empty + ): + expndr = st.expander( + f"Trovato errore data nascita per codice fiscale ({len(dfcod[~mese]) + len(dfnot40[~gg]) + len(df40[~gg40]) + len(dfcod[~anno])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta un'incongruenza relativa alla data di nascita dichiarata e il codice fiscale" + ) + # lista dei df con errori che concateniamo per fare un unico df + frames = [dfnot40[~gg], df40[~gg40], dfcod[~mese], dfcod[~anno]] + result = pd.concat(frames) + make_grid(result.sort_values(by=["Cognome e nome bambino"])) + # settiamo il flag bool per i codfisc che sono presenti in results + df.loc[ + df["Codice fiscale"].isin(result["Codice fiscale"]), "errCodFisc2" + ] = True + + return df + + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errErrorePresenza(df): + # condizione logica + ore_rendicontate_uguale_zero = df["Ore totali rendicontate per il 2020"] == 0 + condizione_logica = ore_rendicontate_uguale_zero & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore presenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (Ore totali rendicontate = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[condizione_logica, "errErrorePresenza"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore presenzae", + "ErrorePresenza", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errAgeChild(df): + + giorni = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + - df["Data di nascita"] + ).dt.days < 90 + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore età bambino (< 90 giorni) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: il bambino ha meno di 3 mesi" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + # settiamo la colonna bool + df.loc[ + condizione_logica, + "errAgeChild", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore età bambino", + "ErroreEtaBambino", + ) + + return df + else: + return df + + +def errErroreDati543(df): + + errore_dati_543p1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + > DATAINIZIOMINIMA + ) + errore_dati_543p2 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + == 0 + ) + + errore_dati_543p3 = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < DATAFINEMASSIMA + ) + + condizione_logica = ( + errore_dati_543p1 & errore_dati_543p2 & errore_dati_543p3 & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore dati 543 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFIne < 05.03.20 e dataInizio > 18.05.20 ore543 = 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + condizione_logica, + "errErroreDati543", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore dati 543", + "ErroreDati543", + ) + + return df + else: + return df + + +def errFineAssistenzaMax4Anni(df): + + giorni = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + - df["Data di nascita"] + ).dt.days > 1464 + + condizione_logica = giorni & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore fine contratto assistenza ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'erorre secondo la condizione: dataFine non può essere oltre 4 anni da dataNascita" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errFineAssistenzaMax4Anni", + ] = True + x = dwnld( + df[giorni].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore fine contratto assistenza", + "ErroreFineContratto", + ) + + return df + else: + return df + + +def errKindergarten_1(df): + + data_nascita = df["Data di nascita"] <= KONTROLLEKINDERGARTEN_DATANASCITA_1 + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + > KONTROLLEKINDERGARTEN_DATAFINEASSISTENZA_1 + ) + condizione_logica = data_nascita & data_fine_assistenza & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita <= 28.02.2017 e dataFine > 15.09.2019)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_1", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 1", + "ErroreKindergarten1", + ) + + return df + else: + return df + + +def errKindergarten_2(df): + + data_nascita = df["Data di nascita"] >= KONTROLLEKINDERGARTEN_DATANASCITA_2 + data_nascita2 = df["Data di nascita"] < pd.to_datetime( + "01.01.2018", format="%d.%m.%Y" + ) + data_fine_ass = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime( + "15.09." + (pd.to_datetime(df["Data di nascita"]).dt.year + 3).astype("str"), + format="%d.%m.%Y", + ) + condizione_logica = data_nascita & data_nascita2 & data_fine_ass & NO_ZERO + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Kindergarten #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataNascita >= 01.03.2017 e dataFine > 15.09 dell'anno di nascita + 3 anni)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + df.loc[ + (condizione_logica), + "errKindergarten_2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Kindergarten 2", + "ErroreKindergarten2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo2(df): + + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= DATAINIZIOMINIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_fine & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #2 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato l'errore secondo la condizione: (dataFine <= 18.05.2020 e finanzCompensativo > 0 )" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo2", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo #2", + "ErroreFinanziamentoCompensativo2", + ) + + return df + else: + return df + + +def errErroreFinanziamentoCompensativo(df): + + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + ore_compensative = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = data_inizio & ore_compensative & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore finanziamento compensativo #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 05.03.2020 e finanzCompensativo > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreFinanziamentoCompensativo", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore finanziamento compensativo", + "ErroreFinanziamentoCompensativo", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_inizio_minima & data_inizio_massima & ore_contrattualizzate & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung", + "ErroreEingewöhnung", + ) + + return df + else: + return df + + +def errFehlerEingewöhnung543Lockdown(df): + + data_inizio_minima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= EINGEWÖHNUNG_DATAINIZIO_MIN + ) + data_inizio_massima = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= EINGEWÖHNUNG_DATAINIZIO_MAX + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio_minima & data_inizio_massima & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Eingewöhnung 543 Lockdown ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataInizio >= 13.02.2020 e dataInizio <= 05.03.2020 e ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errFehlerEingewöhnung543Lockdown", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Eingewöhnung 543 Lockdown", + "ErroreLockdown543", + ) + + return df + else: + return df + + +def errErroreCovid(df): + + data_fine_assistenza = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + < KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_733 = ( + df["Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020"] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + condizione_logica = ( + data_fine_assistenza & (ore_543 | ore_733 | ore_contrattualizzate) & NO_ZERO + ) + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #1 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato trovato l'errore secondo la condizione: (dataFine < 05.03.2020 e Ore543 > 0) oppure (dataFine < 05.03.2020 e Ore733 > 0) oppure (dataFine < 05.03.2020 e finanzCompensativo) > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + (condizione_logica), + "errErroreCovid", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 1", + "ErroreCovid1", + ) + + return df + else: + return df + + +def errErroreCovid2(df): + + data_inizio_ass = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID2_DATAINIZIOASSISTENZA + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + ore_contrattualizzate = ( + df[ + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)" + ] + > 0 + ) + + # non abbiamo messo la condizione per evitare records con ore rendicontate = 0 + if not df[ + (data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate) + ].empty: + expndr = st.expander( + f"Trovato errore Covid #2 ({len(df[(data_inizio_ass & ore_543) | (data_inizio_ass & ore_contrattualizzate)])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (data inizio >= 24.11.2020 e ore543 > 0) oppure (data inizio >= 24.11.2020 e finanzCompensativo > 0)" + ) + make_grid( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + df.loc[ + ( + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ), + "errErroreCovid2", + ] = True + x = dwnld( + df[ + (data_inizio_ass & ore_543) + | (data_inizio_ass & ore_contrattualizzate) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 2", + "ErroreCovid2", + ) + + return df + else: + return df + + +def errErroreCovid3(df): + data_inizio = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= KONTROLLECOVID_DATAINIZIOASSISTENZA + ) + data_fine = ( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + <= KONTROLLECOVID_DATAFINEASSISTENZA2 + ) + ore_543 = ( + df[ + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020" + ] + > 0 + ) + condizione_logica = data_inizio & data_fine & ore_543 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore Covid #3 ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui risulta l'errore secondo la condizione: (dataInizio >= 5/3/20) e (dataFine <= 30/10/20) e (ore543 > 0)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid3", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore Covid 3", + "ErroreCovid3", + ) + + return df + else: + return df + + +def errErroreCovid4(df): + condizione1 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + >= DATAFINEMASSIMA + ) + condizione2 = ( + df["Data inizio contratto (o data inizio assistenza se diversa)"] + <= DATAFINEMASSIMA_COVID4 + ) + condizione_logica = condizione1 & condizione2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato contratti lockdown da controllare (Covid #4) ({len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è soddisfatta la condizione: (5/3/2020 <= dataInizio <= 17/5/2020)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + df.loc[ + condizione_logica, + "errErroreCovid4", + ] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con contratti lockdown da controllare (Covid #4)", + "ErroreCovid4", + ) + + return df + else: + return df + + +def errGesamtstundenVertragszeitraum( + df, +): # incompleto perchè va verificato su più file Excel + # la condizione logica per trovare l'errore + # condizioneerrore1 = ((1920 * (df["GiorniAssistenzaAnnoRiferimento"])) / 366) < df[ + # "Ore totali rendicontate per il 2020" + # ] + + # conta_cod_fiscale = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") == 1 + # ) + # condizione_logica = condizioneerrore1 & conta_cod_fiscale & NO_ZERO + + # presenza errore in caso di codfisc che occorre solo una volta + # df1 = df[condizioneerrore1 & conta_cod_fiscale] + + condizioneerrore2 = ( + ( + 1920 + * ( + df.groupby("Codice fiscale")[ + "GiorniAssistenzaAnnoRiferimento" + ].transform("sum") + ) + / 366 + ) + ) < df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + + condizione_logica = condizioneerrore2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore -Proportion Maximalstunden überschritten- (ATTENZIONE: va verificato!) (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la proporzione delle ore per i giorni di assistenza è inferiore alla somma delle ore rendicontate per il 2020. Secondo la formula: (1920*(giorniAssistenzaAnnoRiferimento)/366) < (oreTotaliRendicontate2020))" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo il flag bool per la tabella finale + df.loc[condizione_logica, "errGesamtstundenVertragszeitraum"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive per durata contrattuale", + "ErroreOreComplessive", + ) + + return df + # se non trovato errore il df è restituito come è stato ricevuto + else: + return df + + +def errSuperatoOreMassime1920(df): + # condizionlogica = ( + # df.groupby("Codice fiscale")["Codice fiscale"].transform("count") > 1 + # ) + condizionelogica2 = ( + df.groupby("Codice fiscale")["Ore totali rendicontate per il 2020"].transform( + "sum" + ) + > 1920 + ) + condizione_logica = condizionelogica2 & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovato errore ore complessive maggiore di 1920 (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui la somma delle ore totali rendicontate per il 2020 è maggiore di 1920" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag per tabella finale + df.loc[condizione_logica, "errSuperatoOreMassime1920"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con errore ore complessive maggiore 1920", + "ErroreOre1920", + ) + + return df + else: + return df + + +def errBambinoInPiuComuni(df): + condizionlogica1 = df.groupby("Codice fiscale")["Comune"].transform("nunique") > 1 + # & NO_ZERO - tolto qui perché nella tabella dei bimbi in più comuni li vogliamo vedere + condizione_logica = condizionlogica1 + if not df[condizione_logica].empty: + + expndr = st.expander( + f"Trovati bambini presenti in più comuni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info("Elenco dei bambini trovati in più comuni (in più file Excel)") + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool per tabella finale + df.loc[condizione_logica, "errBambinoInPiuComuni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini in più comuni", + "errBambinoInPiuComuni", + ) + return df + else: + return df + + +def errPresentiAnnotazioni(df): + condizione = ( + df["Cognome e nome bambino"].str.contains("[@_!#$%^&*()<>?/|}{~:]") == True + ) + condizione_logica = condizione & NO_ZERO + + if not df[condizione_logica].empty: + expndr = st.expander( + f"Trovati bambini con annotazioni (trovati {len(df[condizione_logica])} errori)" + ) + with expndr: + st.info( + "Elenco dei bambini che hanno una annotazione, o direttamente nel nome o nella colonna del numero progressivo (dal quale viene cancellato e aggiunto al nome)" + ) + make_grid(df[condizione_logica].sort_values(by=["Cognome e nome bambino"])) + + # settiamo flag bool + df.loc[condizione_logica, "errPresentiAnnotazioni"] = True + x = dwnld( + df[condizione_logica].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con annotazioni", + "errPresentiAnnotazioni", + ) + return df + else: + return df + + +def errMassimo543(df): + + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("17.05.2020", format="%d.%m.%Y") + + cond2 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("16.11.2020", format="%d.%m.%Y") + cond2b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] >= pd.to_datetime("23.11.2020", format="%d.%m.%Y") + + cond3 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.11.2020", format="%d.%m.%Y") + cond3b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("06.11.2020", format="%d.%m.%Y") + + cond3c = ( + df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("eppan") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bozen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("branzoll") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("freienfeld") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("auer") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("leifers") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("mals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nals") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("welschnofen") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("ratschings") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("pfatten") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("feldthurns") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("sterzing") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bolzano") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("bronzolo") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("trens") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("egna") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("laives") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("malles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("nalles") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("levante") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("racines") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vadena") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("velturno") + | df["Comune di residenza assistente domiciliare all'infanzia"] + .str.lower() + .str.contains("vipiteno") + ) + + if not df[cond1 & cond1b & NO_ZERO].empty: + df.loc[cond1 & cond1b & NO_ZERO, "gg1"] = 74 + else: + df[cond1 & cond1b & NO_ZERO, "gg1"] = 0 + + if not df[cond2 & cond2b & NO_ZERO].empty: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 8 + else: + df.loc[cond2 & cond2b & NO_ZERO, "gg2"] = 0 + + if not df[cond3 & cond3b & cond3c & NO_ZERO].empty: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 2 + else: + df.loc[cond3 & cond3b & cond3c & NO_ZERO, "gg3"] = 0 + + df.insert(13, "massimo543", 0) + + df["massimo543"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * (df["gg1"] + df["gg2"] + df["gg3"]) + + df["massimo543"] = df["massimo543"].astype(int) + + if not df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].empty: + expndr = st.expander( + f"Calcolata colonna massimo ore 543 (trovati {len(df[(cond1 & cond1b & NO_ZERO) | (cond2 & cond2b & NO_ZERO) | (cond3 & cond3b & cond3c & NO_ZERO)])} casi)" + ) + with expndr: + st.info( + "Elenco dei bambini per cui è stato calcolato il valore ore massime 543" + ) + make_grid( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]) + ) + + # settiamo flag bool + df.loc[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO), + "errMassimo543", + ] = True + x = dwnld( + df[ + (cond1 & cond1b & NO_ZERO) + | (cond2 & cond2b & NO_ZERO) + | (cond3 & cond3b & cond3c & NO_ZERO) + ].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo 543 calcolato", + "errMassimo543", + ) + # st.write(df[(cond1 & cond1b) | (cond2 & cond2b) | (cond3 & cond3b & cond3c)]) + return df + else: + return df + + +def errMassimoFC(df): + cond1 = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] <= pd.to_datetime("05.03.2020", format="%d.%m.%Y") + + cond1b = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("18.05.2020", format="%d.%m.%Y") + + cond1c = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] < pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + cond1d = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ] > pd.to_datetime("31.08.2020", format="%d.%m.%Y") + + if not df[cond1 & cond1b & cond1c & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1c & NO_ZERO, "fc"] = (df.loc[cond1 & cond1b & cond1c & NO_ZERO, "Data fine contratto\n(o data fine assistenza se diversa) *"] - df.loc[cond1 & cond1b & cond1c & NO_ZERO, "Data inizio contratto (o data inizio assistenza se diversa)"]).dt.days + 1 + + if not df[cond1 & cond1 & cond1d & NO_ZERO].empty: + df.loc[cond1 & cond1b & cond1d & NO_ZERO, "fc"] = (pd.to_datetime("31.08.2020", format="%d.%m.%Y") - df.loc[cond1 & cond1b & cond1d & NO_ZERO, "Data inizio contratto (o data inizio assistenza se diversa)"]).dt.days + 1 + + df.insert(15, "massimofc", 0) + + df["massimofc"] = ( + ( + ( + 0.055 + * ( + df["Ore totali rendicontate per il 2020"] + / df["GiorniAssistenzaAnnoRiferimento"] + ) + ) + + df["Ore totali rendicontate per il 2020"] + ) + / df["GiorniAssistenzaAnnoRiferimento"] + ) * df["fc"] + + df["massimofc"] = df["massimofc"].astype(int) + + if not df[(cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1 & cond1d & NO_ZERO)].empty: + expndr = st.expander("Calcolata colonna massimo FC") + with expndr: + st.info("Tabella con valore calcolato massimo FC") + make_grid(df[(cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1 & cond1d & NO_ZERO)].sort_values(by=["Cognome e nome bambino"])) + # non settiamo il flag bool perché non ci serve + x = dwnld( + df[(cond1 & cond1b & cond1c & NO_ZERO) | (cond1 & cond1 & cond1d & NO_ZERO)].sort_values(by=["Cognome e nome bambino"]), + "Scaricare tabella con bambini con valore massimo FC calcolato", + "errMassimoFC", + ) + return df + else: + return df + + +# FINE CHECKS +################################## + + +def make_grid(dff): + # togliamo le colonne bool + dff = drop_columns(dff) + gridOptions = buildGrid(dff) + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True) + + +def get_data(uploaded_files, anno_riferimento): + dfout = None + st.info("Sono stati caricati " + str(len(uploaded_files)) + " files") + status = st.empty() + for uploaded_file in uploaded_files: + try: + status.info("[*] " + uploaded_file.name + " caricato") + df = pd.read_excel(uploaded_file, usecols="A:M") + except: + st.error(uploaded_file.name + " non è un file Excel") + continue + + # lasciamo prepare_data qui? + try: + status.info(f"[*] {uploaded_file.name} elaborato") + df = prepare_data(df, uploaded_file, anno_riferimento) + except: + st.error( + f"{uploaded_file.name} --> ERRORE CONTROLLO GENERALE --> Il file non viene usato per l'elaborazione" + ) + continue + + # se dfout non esiste lo creiamo + if dfout is None: + dfout = pd.DataFrame(columns=df.columns) + dfout = df + else: + # inserire qui il controllo del nome ente, che deve essere lo stesso per i file caricati? + dfout = pd.concat([dfout, df]) + + # ora sono tutti concatenati e possiamo restituire il dataframe + if dfout is not None: + status.success( + "[*] Tutti i dati sono stati elaborati - PER INIZIARE DA CAPO: RICARICARE LA PAGINA" + ) + + # ci servono inizializzate per il calcolo delle ora massime 543 + dfout["gg1"] = 0 + dfout["gg2"] = 0 + dfout["gg3"] = 0 + dfout["fc"] = 0 #server per calcolo massimo finanziamento compensativo + + return dfout + + +def choose_checks2(): + checks = {} + st.write("") + a = 1 + # creiamo le checkbox e i valori dinamicamente in base al dictionary che contiene + # la lista degli errori + expndr = st.expander("SELEZIONE CONTROLLI DA ESEGUIRE", expanded=True) + c1, c2, c3, c4 = expndr.columns(4) + with expndr: + st.write("") + attivatutti = expndr.checkbox( + "Selezionare/deselezionare tutti i controlli", value=True + ) + for e in ERRORDICT.keys(): + # creiamo i nomi delle variabili in modo dinamico + locals()[f"{e}"] = locals()[f"c{a}"].checkbox( + ERRORDICT[e], value=attivatutti, key=e + ) + if a == 4: + a = 1 + else: + a = a + 1 + # scriviamo nel dict il nome del controllo e il valore bool della checkbox + checks[e] = locals()[f"{e}"] + + return checks + + +def prepare_data(df, uploaded_file, anno_riferimento): + + # DOBBIAMO RINOMINARE TUTTE LE COLONNE PERCHÉ ARRIVANO + # IN TEDESCO E ITALIANO - USIAMO ITALIANO + # E SPERIAMO SIANO TUTTE NELLO STESSO ORDINE + df.columns = [ + "Numero \nprogressivo", + "Cognome e nome bambino", + "Data di nascita", + "Codice fiscale", + "Assistente domiciliare all'infanzia", + "Comune di residenza assistente domiciliare all'infanzia", + "Data inizio contratto (o data inizio assistenza se diversa)", + "Data fine contratto\n(o data fine assistenza se diversa) *", + "Ore di assistenza \n ai sensi della delibera\nn. 666/2019", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 543_1025/2020", + "Ore contrattualizzate non erogate\nai sensi della delibera\nn. 733/2020", + "Ore contrattualizzate non erogate\nnella fase 2 (finanziamento compensativo)", + "Ore totali rendicontate per il 2020", + ] + + # estraiamo comune e nome ente da dove ci aspettiamo che siano + # nel dataframe creato dal singolo file Excel + traeger = df.iloc[2] + # ente e traeger in e4/e5 + if type(traeger[4]) == type("string"): + traeger = traeger[4].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[4] + # ente/traeger in d4/d5 + else: + traeger = traeger[3].title() + gemeinde = df.iloc[3] + gemeinde = gemeinde[3] + + # cancelliamo le righe che non ci servono + df = df.drop(labels=range(0, 8), axis=0) + + # dobbiamo intercettare se c'è un * nella colonna del numero progressivo + # sostituire l'asterisco con 99 e aggiungere l'asterisco al nome + cond = df["Numero \nprogressivo"] == "*" + df.loc[cond, "Cognome e nome bambino"] += " *" + df.loc[cond, "Numero \nprogressivo"] = 99 + + # prima convertiamo la colonna in numerica, forzando NaN sui non numerici + df["Numero \nprogressivo"] = pd.to_numeric( + df["Numero \nprogressivo"], errors="coerce" + ) + + # selezioniamo solo le righe che hanno un valore numerico in *Numero progressivo* + # in questo modo eliminiamo le righe inutili dopo l'ultimo *numero progressivo* + validi = df["Numero \nprogressivo"].notna() + + # teniamo solo record validi + df = df[validi] + + # elimiamo colonne che sono servono più + df = df.drop(["Numero \nprogressivo"], axis=1) + + # se troviamo data fine vuota la mettiamo al 31/12 dell'anno riferimento + condizione = pd.isnull( + df["Data fine contratto\n(o data fine assistenza se diversa) *"] + ) + df.loc[ + condizione, "Data fine contratto\n(o data fine assistenza se diversa) *" + ] = "12-31-" + str(anno_riferimento) + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + + # convertiamo colonne in data + try: + df["Data di nascita"] = df["Data di nascita"].astype("datetime64[ns]") + except: + st.error(f"{uploaded_file.name} --> data di nascita contiene valori non data") + try: + df["Data fine contratto\n(o data fine assistenza se diversa) *"] = df[ + "Data fine contratto\n(o data fine assistenza se diversa) *" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data fine contratto contiene valori non data" + ) + + try: + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ].astype("datetime64[ns]") + except: + st.error( + f"{uploaded_file.name} --> data inizio contratto contiene valori non data" + ) + + # creiamo due nuove colonne e le riempiamo con comune ed ente + # estratti prima + df.insert(1, "Comune", gemeinde) + df.insert(1, "Ente", traeger) + + # sostituiamo tutti i NaN con *0* + df = df.fillna(0) + + # scriviamo anche il nome del file perché non si sa mai che non possa servire + df.insert(0, "filename", uploaded_file.name) + # df['filename'] = uploaded_file.name + + # assicuriamo che codice fiscale sia in maiuscolo + df["Codice fiscale"] = df["Codice fiscale"].str.upper() + + # aggiungiamo le colonne che ci servono più tardi per i codici errore + # e assegniamo un valore dummy + dfbool = make_bool_columns(df) + + return dfbool + + +def compute_hours(df, ar): + ar = int(ar) # convertiamo anno riferimento in *int* + df["inizioNorm"] = df[ + "Data inizio contratto (o data inizio assistenza se diversa)" + ] # intanto inseriamo i valori che ci sono + df["fineNorm"] = df["Data fine contratto\n(o data fine assistenza se diversa) *"] + + # se data inizio minore di anno riferimento allora mettiamo il 1. gennaio dell'anno riferimento + iniz = df["inizioNorm"].dt.year < ar # condizione logica + df.loc[iniz, "inizioNorm"] = "01-01-" + str( + ar + ) # cerchiamo i valori < anno riferimento e sostituiamo con 01/01 + + fin = df["fineNorm"].dt.year > ar # condizione logica + df.loc[fin, "fineNorm"] = "12-31-" + str(ar) # sostituzione + df.insert( + 9, "GiorniAssistenzaAnnoRiferimento", 0 + ) # aggiungiamo colonna e mettiamo anno riferimento + df["GiorniAssistenzaAnnoRiferimento"] = ( + df["fineNorm"] - df["inizioNorm"] + ).dt.days + 1 # calcolo giorni anno riferimento. +1 perché il giorno fine va incluso + # df = df.drop(['inizio','fine'], axis=1) # le colonne non servono più + return df + + +def drop_columns(df): + + for k in ERRORDICT: + df = df.drop([k], axis=1) + + # servivano per calcolare ore massime 543 + # non sicuro che sia il posto migliore per dropparle + df = df.drop(["gg1", "gg2", "gg3", "fc"], axis=1) + + return df + + +def dwnld(df, k, ff): + if ff != "soloerrori": + df = drop_columns(df) + + f = df.to_csv(sep=";").encode( + "utf-8-sig" + ) # dobbiamo usare questo encoding altrimenti windoof di m***a sballa Umlaute + st.download_button( + label=k, + data=f, + file_name=ff + ".csv", + mime="text/csv", + key=k, + ) + return "x" # inutile + + +def make_df_solo_errori(dffinal): + # creiamo la condizione logica + # almeno un errore per tipologia errore + for e in ERRORDICT.keys(): + # non lo vogliamo nel df degli errori perché sono tanti, troppi + if e == "errMassimo543": + continue + # prima instanziazione di "condizione" + # in questo modo viene creato con type giusto + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione = dffinal[e] == True + else: + # soluzione semplice: concateniamo le condizioni + # per i controlli fatti + condizione = condizione | dffinal[e] == True + # creiamo df con soli record con errore + + dffinal = dffinal[condizione] + # droppiamo la colonna che non vogliamo + dffinal = dffinal.drop(["errMassimo543"], axis=1) + + return dffinal + + +def genera_report(df): + st.info("Generazione file riassunto analisi") + workbook = xlsxwriter.Workbook("riassuntoAutomatico.xlsx") + worksheet = workbook.add_worksheet() + row = 0 + col = 0 + worksheet.write(row, col, "Riassunto analisi") + nr_bambini = df["Codice fiscale"].nunique() + row += 2 + worksheet.write(row, col, f"Trovati errori per {nr_bambini} bambini") + row += 2 + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + nrerr = len(df[condizione]) + if nrerr > 0: + worksheet.write( + row, col, f"Trovate {nrerr} occorrenze per il controllo {ERRORDICT[e]}" + ) + row += 1 + + row += 2 + bold = workbook.add_format({"bold": True}) + # start riassunto per tipo errore + for e in ERRORDICT: + if e == "errMassimo543": + continue + condizione = df[e] == True + df_bambini = df[condizione] + nrerr = len(df_bambini) + if nrerr > 0: + worksheet.write(row, col, f"{ERRORDICT[e]}", bold) + row += 2 + df_bimbi = df_bambini.sort_values( + by="Cognome e nome bambino", ascending=True + ) # , inplace=True) + for i, r in df_bimbi.iterrows(): + n = r["Cognome e nome bambino"] + c = r["Codice fiscale"] + nato = r["Data di nascita"] + comune = r["Comune"] + worksheet.write(row, col + 1, f"{n}") + worksheet.write(row, col + 2, f"{c}") + worksheet.write(row, col + 3, f"{nato}") + worksheet.write(row, col + 4, f"{comune}") + row += 1 + row += 1 + workbook.close() + + ddff = pd.read_excel("riassuntoAutomatico.xlsx", index_col=False) + ddff.reset_index(drop=True, inplace=True) + file = ddff.to_csv(sep=";").encode("utf-8-sig") + st.download_button( + label="Scarica riassunto", + data=file, + file_name="riassuntoAutomaticoDati.csv", + mime="text/plain", + key="fileRiassunto", + ) + + +def app(): + + st.header("FAMILIENAGENTUR - AGENZIA PER LA FAMIGLIA") + st.subheader("Controllo errori TAGESMÜTTER (v. 1.0.0)") + dfout = None + + # carichiamo qui la tabella dello storico?? + # if path.exists("storico.xlsx"): + # c1, c2 = st.columns(2) + # c1.info("Trovato file storico") + # storico = c2.checkbox("caricare file storico?") + # if storico: + # pass + + # anno_riferimento = 2020 + uploaded_files = st.file_uploader( + "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True + ) + + anno_riferimento = st.selectbox("ANNO RIFERIMENTO", ("2020", "2021", "2022")) + + checks = choose_checks2() + + f = st.form("Auswahl", clear_on_submit=True) + flag = 0 + + with f: + # soluzione un po' assurda, ma vogliamo spostare gli expander fuori dalla form + # altrimenti non possiamo usare il button per download + submit = f.form_submit_button("Iniziare elaborazione e controllo errori") + if submit: + if len(uploaded_files) == 0: + st.error("Nessun file caricato!") + else: + flag = 1 + + # se button pigiato, allora esegui... + if flag == 1: + dfout = get_data(uploaded_files, anno_riferimento) + if dfout is not None: + dfout = compute_hours(dfout, anno_riferimento) + dffinal = check_data2(dfout, checks) + st.write("") + st.info("Tabelle elaborate") + + # la tabella finale, contiene TUTTI i record + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinal.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinal.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON TUTTI I DATI", + "tuttidati", + ) + + # la tabella finale che contiene soltanto record con ALMENO UN ERRORE + dffinalerr = make_df_solo_errori(dffinal) + expndr = st.expander( + "TABELLA FINALE ELABORATA - SOLO ERRORI (senza massimo543 e somme ore)" + ) + with expndr: + # facciamo la grid qui così evitiamo che vengano + # droppate le colonne flag bool + gridOptions = buildGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]) + ) + AgGrid( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + dwnld( + dffinalerr.sort_values(by=["Cognome e nome bambino"]), + "SCARICARE TABELLA CON SOLO ERRORI", + "soloerrori", + ) + + # salviamo qui la tabella finale?? + st.write("") + st.write("") + try: + dffinalerr.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except: + st.error("ERRORE salvataggio file storico") + + # try: + genera_report(dffinalerr) + # except: + # st.error("Errore durante generazione automatica report") + + +app() diff --git a/pages/prospetto rendicontazione microstrutture miste_Max.xlsx b/pages/prospetto rendicontazione microstrutture miste_Max.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e0518d0bcbb5ef7739707b6c9bba5e67ee8c8329 Binary files /dev/null and b/pages/prospetto rendicontazione microstrutture miste_Max.xlsx differ diff --git a/pages/prospetto rendicontazione via combattenti 2019.xlsx b/pages/prospetto rendicontazione via combattenti 2019.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d3524655100e10c31f597145aa191b6c5cdfc999 Binary files /dev/null and b/pages/prospetto rendicontazione via combattenti 2019.xlsx differ diff --git a/pages/riassuntoAutomatico.xlsx b/pages/riassuntoAutomatico.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..43ca88d93a3be2e89eab4cb568da99981187a9d7 Binary files /dev/null and b/pages/riassuntoAutomatico.xlsx differ diff --git a/pages/storico.xlsx b/pages/storico.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a6352f0a604ebc3b844d448beccd9a6d442f22ef Binary files /dev/null and b/pages/storico.xlsx differ diff --git a/pages/test.csv b/pages/test.csv new file mode 100644 index 0000000000000000000000000000000000000000..f4a6340c22a6b4a7de4f7f48ce008bc3fa63c7f8 --- /dev/null +++ b/pages/test.csv @@ -0,0 +1,188 @@ +;filename;Cognome e nome bambino;Ente;Comune;Data di nascita;Codice fiscale;Assistente domiciliare all'infanzia;Comune di residenza assistente domiciliare all'infanzia;Data inizio contratto (o data inizio assistenza se diversa);GiorniAssistenzaAnnoRiferimento;"Data fine contratto +(o data fine assistenza se diversa) *";"Ore di assistenza + ai sensi della delibera +n. 666/2019";"Ore contrattualizzate non erogate +ai sensi della delibera +n. 543_1025/2020";massimo543;"Ore contrattualizzate non erogate +ai sensi della delibera +n. 733/2020";"Ore contrattualizzate non erogate +nella fase 2 (finanziamento compensativo)";Ore totali rendicontate per il 2020;errCodFisc1;errCodFisc2;errAgeChild;errInizioMinoreFine;errErrorePresenza;errErroreDati543;errFineAssistenzaMax4Anni;errKindergarten_1;errKindergarten_2;errErroreFinanziamentoCompensativo;errErroreFinanziamentoCompensativo2;errErroreCovid;errErroreCovid2;errErroreCovid3;errErroreCovid4;errFehlerEingewöhnung;errFehlerEingewöhnung543Lockdown;errFehlerEingewöhnung543Notbetreuung;errGesamtstundenVertragszeitraum;errSuperatoOreMassime1920;errBambinoInPiuComuni;errPresentiAnnotazioni;errOreRendicontateZero;errSommaOre;errMassimoFC;gg1;gg2;gg3;inizioNorm;fineNorm +9;Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx;Ajardi Josef;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ahrntal;2019-10-02;JRDJSF19R02B220Y;Kirchler Judith;St. Peter In Ahrntal;2020-02-24;312;2020-12-31;641.5;194.5;233;0;50.75;886.75;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;0;2020-02-24;2020-12-31 +31;Erklärung Gemeinden Jahr 2020 Ahrntal.xlsx;Ruiu Nina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ahrntal;2017-03-25;RUINNI17C65B220Y;Kirchler Irmgard;Ahrntal;2018-03-01;287;2020-10-13;554.75;176.5;202;0;54.5;785.75;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-10-13 +10;Erklärung Gemeinden Jahr 2020 Algund.xlsx;Bertagnolli Julius;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Algund;2017-08-10;BRTJLS17M10I729H;Troger Moser Anna;Algund;2020-03-20;42;2020-04-30;0.0;73.0;0;0;0.0;73.0;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-03-20;2020-04-30 +11;Erklärung Gemeinden Jahr 2020 Algund.xlsx;Ciaramella Lageder Giacomo Clemens;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Algund;2019-12-22;CRMGMC19T22F132F;Borarosova Zaneta ;Meran;2020-09-07;56;2020-11-01;68.5;0.0;0;0;0.0;68.5;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-09-07;2020-11-01 +16;Erklärung Gemeinden Jahr 2020 Algund.xlsx;Gruber Emma;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Algund;2018-05-27;GRBMME18E67F132P;Troger Moser Anna;Algund;2020-03-02;305;2020-12-31;753.5;267.0;300;0;96.5;1117.0;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;0;2020-03-02;2020-12-31 +18;Erklärung Gemeinden Jahr 2020 Algund.xlsx;Hölzl Felicia Victoria;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Algund;2017-11-16;HLZFCV17S56F132E;Willibald Maria Anna;Algund;2019-09-30;366;2020-12-31;716.5;220.0;236;0;119.5;1056.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +21;Erklärung Gemeinden Jahr 2020 Algund.xlsx;Maturilli Anna Maria;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Algund;2017-06-23;MTRNMR17H63F132N;De Arruda Ruth;Meran;2020-01-01;268;2020-09-24;427.0;237.5;164;0;-70.0;594.5;;;;;;;;;True;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-09-24 +8;Erklärung Gemeinden Jahr 2020 Auer.xlsx;Billi Lorenzo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Auer;2020-02-12;BLLLNZ20B12A952J;Huber Melanie;Margreid;2020-11-09;53;2020-12-31;70.75;24.0;14;0;0.0;94.75;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Bozen.xlsx;Alia Amelia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bozen;2018-11-21;LAIMLA18S61A952S;Kienzl Karin Anna;Leifers;2019-04-15;277;2020-10-03;856.75;250.0;297;0;7.0;1113.75;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-10-03 +15;Erklärung Gemeinden Jahr 2020 Bozen.xlsx;Huber Anna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bozen;2018-11-15;HBRNNA18S55A952Y;Molon Karoline;Bozen;2020-03-02;305;2020-12-31;426.5;209.0;233;0;210.5;846.0;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;2;2020-03-02;2020-12-31 +22;Erklärung Gemeinden Jahr 2020 Bozen.xlsx;Pircher Elsa Katharina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bozen;2020-02-15;PRCLKT20B55I729Y;Kaserer Monika;Schlanders;2020-11-03;59;2020-12-31;71.0;16.0;11;0;0.0;87.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-03;2020-12-31 +25;Erklärung Gemeinden Jahr 2020 Bozen.xlsx;Stampfl Johanna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bozen;2017-01-07;STMJNN17A47A952V;Plattner Julia;Terlan;2019-09-02;244;2020-08-31;248.0;104.0;114;0;24.0;376.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-31 +31;Erklärung Gemeinden Jahr 2020 Bozen.xlsx;Viaro Camilla;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bozen;2016-10-24;VRICLL16R64L378G;Molon Karoline;Bozen;2018-09-03;63;2020-03-03;188.0;0.0;0;0;0.0;188.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-03-03 +14;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Keim Iaco;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2017-07-27;KMECIA17L27B160E;Stablum Martina;Brixen;2019-10-09;127;2020-05-06;90.0;108.0;0;0;54.0;252.0;;;;;;;;;;;True;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-06 +21;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Lüling Gabriel;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2017-02-23;LLNGRL17B23B160G;Stablum Martina;Brixen;2018-10-29;251;2020-09-07;278.75;195.25;161;0;73.0;547.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-07 +25;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Oschmann Carl Cosimo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2017-07-23;SCHCLC17L23B160P;Stablum Martina;Brixen;2019-10-18;267;2020-09-23;280.5;136.0;130;0;56.0;472.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-23 +30;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Platter Felix;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2017-04-28;PLTFLX17D28B160Z;Agreiter Theolinda;Brixen;2018-07-16;267;2020-09-23;268.0;108.0;123;0;69.0;445.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-23 +52;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Weissteiner Maximilian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2018-07-16;WSSMML18L16B160Z;Tschiggfrei Monika;Brixen;2020-11-09;53;2020-12-31;58.25;9.0;10;0;0.0;67.25;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +53;Erklärung Gemeinden Jahr 2020 Brixen.xlsx;Witcher Noah Sebastian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Brixen;2017-03-04;WTCNSB17C04B160X;Tschiggfrei Monika;Brixen;2020-01-14;256;2020-09-25;286.5;100.0;116;0;16.0;402.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-14;2020-09-25 +9;Erklärung Gemeinden Jahr 2020 Burgstall.xlsx;Mazohl Mari;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Burgstall;2018-09-24;MZHMRA18P64F132P;Czuchin Rosa ;Lana;2019-04-23;235;2020-08-22;329.5;165.75;179;0;75.0;570.25;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-08-22 +11;Erklärung Gemeinden Jahr 2020 Burgstall.xlsx;Vent Ludwig;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Burgstall;2018-09-17;VNTLWG18P17F132O;Troger Moser Anna;Algund;2020-03-02;305;2020-12-31;480.5;156.0;186;0;56.0;692.5;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;0;2020-03-02;2020-12-31 +16;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Burkhart Nele;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2017-02-01;BRKNLE17B41B220I;Keppel Carina;Gais;2018-08-27;251;2020-09-07;641.5;208.0;226;0;-81.0;768.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-07 +23;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Gatterer Banna Amira;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2017-04-03;GTTMRA17D43B220Y;Oberleiter Maria Magdalena ;Percha;2019-01-08;366;2020-12-31;834.0;275.0;286;0;168.5;1277.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +43;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Longo Giada;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2017-05-28;LNGGDI17E68B220Z;Keppel Carina;Gais;2018-09-14;366;2020-12-31;582.5;102.0;163;0;47.0;731.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +51;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Obgriesser Niklas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2017-02-26;BGRNLS17B26B220E;Bacher Helga;Bruneck;2017-12-04;252;2020-09-08;293.0;183.5;188;0;164.5;641.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-08 +65;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Schwärzer Anna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2019-10-28;SCHNNA19R68B220L;Gartner Annemarie;Bruneck;2020-08-24;7;2020-08-30;20.5;0.0;0;0;0.0;20.5;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-08-24;2020-08-30 +68;Erklärung Gemeinden Jahr 2020 Bruneck.xlsx;Steger Fiona;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Bruneck;2019-05-23;STGFNI19E63B220P;Gartner Sabine;Pfalzen;2020-03-04;64;2020-05-06;3.75;130.0;0;0;0.0;133.75;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-03-04;2020-05-06 +10;Erklärung Gemeinden Jahr 2020 Deutschnofen.xlsx;Werner Emma;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Deutschnofen;2017-12-27;WRNMME17T67A952M;Zelger Sara;Karneid;2020-09-01;122;2020-12-31;213.0;16.0;15;0;0.0;229.0;;;;;;;;;True;;;;;;;;;;;;;;;;;0;8;0;2020-09-01;2020-12-31 +11;Erklärung Gemeinden Jahr 2020 Eppan.xlsx;Cellamare Camilla;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Eppan;2017-09-20;CLLCLL17P60F132P;Mathà Renate;Eppan;2020-07-21;56;2020-09-14;151.0;0.0;0;0;0.0;151.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-07-21;2020-09-14 +18;Erklärung Gemeinden Jahr 2020 Eppan.xlsx;Fabris Nathan;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Eppan;2020-02-09;FBRNHN20B09F132A;Oberhofer Kathrin;Eppan;2020-11-09;53;2020-12-31;54.0;12.0;9;0;0.0;66.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +21;Erklärung Gemeinden Jahr 2020 Eppan.xlsx;Messner Jakob;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Eppan;2017-11-30;MSSJKB17S30F132S;Ambach Maria;Eppan;2019-08-01;262;2020-09-18;825.75;363.5;365;0;105.25;1294.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-18 +24;Erklärung Gemeinden Jahr 2020 Eppan.xlsx;Pramstrahler Josef;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Eppan;2019-06-13;PRMJSF19H13A952Z;Mathà Renate;Eppan;2020-03-16;16;2020-03-31;0.0;23.0;0;0;0.0;23.0;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-03-16;2020-03-31 +10;Erklärung Gemeinden Jahr 2020 Feldthurns.xlsx;Crepaz Amelie;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Feldthurns;2018-01-01;CRPMLA18A41B160K;Zanesco Lisa;Feldthurns;2020-03-02;305;2020-12-31;358.75;141.5;153;0;56.5;556.75;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;2;2020-03-02;2020-12-31 +13;Erklärung Gemeinden Jahr 2020 Gais.xlsx;Schwärzer Anna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gais;2019-10-28;SCHNNA19R68B220L;Gartner Annemarie;Bruneck;2020-08-31;123;2020-12-31;250.0;0.0;16;0;0.0;250.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;0;2020-08-31;2020-12-31 +14;Erklärung Gemeinden Jahr 2020 Gargazon.xlsx;Malfatti Jonas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gargazon;2017-05-18;MLFJNS17E18F132I;Schölzhorn Sonja;Gargazon;2019-01-02;265;2020-09-21;371.75;189.0;194;0;134.0;694.75;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-21 +18;Erklärung Gemeinden Jahr 2020 Gargazon.xlsx;Santner Lenz;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gargazon;2018-01-30;SNTLNZ18A30F132R;Ladurner Irene;Marling;2020-11-12;50;2020-12-31;63.0;17.5;12;0;0.0;80.5;;;;;;;;;;;;;;;;;;True;;;True;;;;;0;8;0;2020-11-12;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Graun.xlsx;Edobor Evidence;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Graun im Vinschgau;2019-07-19;DBRVNC19L59A952Z;Oswald Maria Pia;Mals i.V.;2020-11-03;59;2020-12-31;21.0;98.75;20;0;0.0;119.75;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;2;2020-11-03;2020-12-31 +10;Erklärung Gemeinden Jahr 2020 Graun.xlsx;Imonsili Mercy;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Graun im Vinschgau;2018-04-23;MNSMCY18D63A952N;Oswald Maria Pia;Mals i.V.;2020-06-22;193;2020-12-31;369.0;92.0;23;0;0.0;461.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;2;2020-06-22;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Gsies.xlsx;Haller Toni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gsies;2016-12-14;HLLTNO16T14B220U;Kargruber Maria;Gsies;2020-07-06;31;2020-08-05;105.0;0.0;0;0;0.0;105.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-07-06;2020-08-05 +9;Erklärung Gemeinden Jahr 2020 Gsies.xlsx;Haller Toni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gsies;2016-12-14;HLLTNO16T14B220U;Kargruber Maria;Gsies;2019-04-03;187;2020-07-05;130.5;189.0;221;0;240.0;559.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-07-05 +14;Erklärung Gemeinden Jahr 2020 Gsies.xlsx;Seiwald Silas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Gsies;2016-11-08;SWLSLS16S08B220U;Auer Petra;Percha;2019-07-04;247;2020-09-03;598.5;237.25;272;0;72.75;908.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-03 +11;Erklärung Gemeinden Jahr 2020 Hafling.xlsx;Eschgfaeller Marie;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Hafling;2017-12-22;SCHMRA17T62A952K;Plattner Martina;Hafling;2019-07-01;366;2020-12-31;888.0;264.0;280;0;97.75;1249.75;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +14;Erklärung Gemeinden Jahr 2020 Kaltern.xlsx;Hafner Paul;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kaltern;2018-05-20;HFNPLA18E20F132Q;Oberhofer Kathrin;Eppan;2020-02-18;79;2020-05-06;12.25;117.0;0;0;0.0;129.25;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-02-18;2020-05-06 +32;Erklärung Gemeinden Jahr 2020 Kaltern.xlsx;Sinn Sebastian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kaltern;2019-03-22;SNNSST19C22A952Q;Peterlin Verena;Kaltern;2020-03-09;120;2020-07-06;0.0;105.0;0;0;94.0;199.0;;;;;;;;;;True;;;;True;True;;;;;;;;;;;0;0;0;2020-03-09;2020-07-06 +9;Erklärung Gemeinden Jahr 2020 Karneid.xlsx;Bozzano Pietro;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Karneid;2017-01-26;BZZPTR17A26B160X;Covi Sibylle;Karneid;2018-10-08;127;2020-05-06;174.0;210.0;0;0;0.0;384.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-06 +13;Erklärung Gemeinden Jahr 2020 Karneid.xlsx;Rieder Fabian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Karneid;2017-01-08;RDRFBN17A08B160U;Covi Sibylle;Karneid;2020-01-20;108;2020-05-06;68.0;104.0;0;0;0.0;172.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-20;2020-05-06 +9;Erklärung Gemeinden Jahr 2020 Kastelbell-Tschars.xlsx;Corduneanu Dorian *;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kastelbell-Tschars;2017-04-05;CRDDRN17D05I729Y;Prantl Stefanie;Kastelbell/Tschars;2018-01-05;127;2020-05-06;151.5;108.0;0;0;0.0;259.5;;;;;;;;;;;;;;;;;;;;;;True;;;;0;0;0;2020-01-01;2020-05-06 +10;Erklärung Gemeinden Jahr 2020 Kastelruth.xlsx;Gostner Noah;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kastelruth;2017-12-18;GSTNHO17T18B160K;Bernard Nadine;Kastelruth;2019-03-21;276;2020-10-02;674.0;258.0;283;0;125.25;1057.25;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-10-02 +14;Erklärung Gemeinden Jahr 2020 Kiens.xlsx;Hochgruber Raphael;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kiens;2017-11-04;HCHRHL17S04B220O;Leiter Manuela;St.Lorenzen;2019-09-16;366;2020-12-31;768.5;230.0;239;0;69.0;1067.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +21;Erklärung Gemeinden Jahr 2020 Kiens.xlsx;Weger Mathe Elisabeth;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kiens;2018-08-11;WGRMHL18M51B220M;Tasser Margit;St.Lorenzen;2020-11-09;53;2020-12-31;89.5;27.5;17;0;0.0;117.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Klausen.xlsx;Bekoe Lucia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Klausen;2017-10-10;BKELCU17R50A952D;Duchova Dana;Lajen;2020-01-18;253;2020-09-26;886.0;414.0;389;0;30.0;1330.0;;;;;;;;;True;;;;;;;;;;True;;;;;;;74;0;0;2020-01-18;2020-09-26 +9;Erklärung Gemeinden Jahr 2020 Klausen.xlsx;Frei Gasser Mia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Klausen;2017-03-25;FRGMIA17C65B160L;Agreiter Theolinda;Brixen;2018-06-25;260;2020-09-16;450.0;180.0;202;0;80.0;710.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-16 +8;Erklärung Gemeinden Jahr 2020 Kurtatsch.xlsx;Barcatta Lisa;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Kurtatsch;2018-11-07;BRCLSI18S47A952V;Peer Petra;Kurtatsch;2020-11-09;53;2020-12-31;98.0;26.25;18;0;0.0;124.25;;;;;;;;;;;;;;;;;;True;;;True;;;;;0;8;0;2020-11-09;2020-12-31 +10;Erklärung Gemeinden Jahr 2020 Lana.xlsx;D´Altri Stella;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2019-02-21;DLTSLL19B61A944K;Andergassen Ruth;Lana;2020-02-18;79;2020-05-06;19.0;122.5;0;0;0.0;141.5;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-02-18;2020-05-06 +12;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Gasser Lara;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2017-02-08;GSSLRA17B48F132D;Kuprian Alexandra;Lana;2020-08-03;40;2020-09-11;137.75;0.0;0;0;0.0;137.75;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-08-03;2020-09-11 +13;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Goegele Maria;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2016-11-22;GGLMRA16S62F132J;Kofler Gertraud ;Lana;2018-07-16;178;2020-06-26;117.5;90.0;114;0;67.0;274.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-06-26 +28;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Orlando Amy;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2017-05-06;RLNMYA17E46F132T;Schwienbacher Hanna;Lana;2019-10-01;160;2020-06-08;124.0;102.0;126;0;48.0;274.0;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-06-08 +29;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Pejic Milica;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2017-06-08;PJCMLC17H48F132R;Lasakova Ivana;Lana;2019-03-26;260;2020-09-16;473.0;161.0;187;0;26.0;660.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-16 +43;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Wassler Alex;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2018-06-02;WSSLXA18H02A952T;Troger Moser Anna;Algund;2020-03-02;217;2020-10-04;7.0;110.5;88;0;143.0;260.5;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;0;0;2020-03-02;2020-10-04 +45;Erklärung Gemeinden Jahr 2020 Lana.xlsx;Wenter Leo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Lana;2017-08-01;WNTLEO17M01F132R;Kofler Gertraud ;Lana;2018-05-15;274;2020-09-30;644.0;231.0;257;0;77.0;952.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-30 +8;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Alia Amelia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2018-11-21;LAIMLA18S61A952S;Kienzl Karin Anna;Leifers;2020-10-04;89;2020-12-31;288.0;66.0;39;0;0.0;354.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;2;2020-10-04;2020-12-31 +9;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Barbi Serena;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2017-10-25;BRBSRN17R65A952R;Huber Jessica;Pfatten;2018-08-27;366;2020-12-31;1070.5;318.0;350;0;138.0;1526.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;2;2020-01-01;2020-12-31 +11;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Cellamare Camilla;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2017-09-20;CLLCLL17P60F132P;Mathà Renate;Eppan;2019-09-02;202;2020-07-20;317.0;192.5;195;0;24.0;533.5;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-07-20 +13;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Coser Anna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2019-05-14;CSRNNA19E54F132F;Huber Jessica;Pfatten;2020-03-02;305;2020-12-31;339.0;121.75;139;0;46.5;507.25;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;2;2020-03-02;2020-12-31 +14;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Coser Arthur;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2017-07-18;CSRRHR17L18F132W;Huber Jessica;Pfatten;2018-01-11;366;2020-12-31;446.5;136.25;143;0;44.0;626.75;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;2;2020-01-01;2020-12-31 +36;Erklärung Gemeinden Jahr 2020 Leifers.xlsx;Todde Nicoló;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Leifers;2019-04-28;TDDNCL19D28A952R;Kienzl Karin Anna;Leifers;2020-08-24;130;2020-12-31;601.75;92.75;53;0;0.0;694.5;;;;;;;;;;;;;;;;;;;True;;;;;;;0;8;2;2020-08-24;2020-12-31 +17;Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx;Punter Julius;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Mals i. V.;2017-06-12;PNTJLS17H12A952S;Weisenhorn Annamaria;Mals i.V.;2020-03-03;11;2020-03-13;6.0;18.0;0;0;0.0;24.0;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-03-03;2020-03-13 +18;Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx;Punter Emil;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Mals i. V.;2017-06-12;PNTMLE17H12A952H;Weisenhorn Annamaria;Mals i.V.;2020-03-03;11;2020-03-13;6.0;18.0;0;0;0.0;24.0;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-03-03;2020-03-13 +24;Erklärung Gemeinden Jahr 2020 Mals i. V..xlsx;Usom Best Daniel;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Mals i. V.;2017-03-15;SMBDNL17C15A952L;Oswald Maria Pia;Mals i.V.;2020-05-18;110;2020-09-04;213.0;0.0;0;0;0.0;213.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-05-18;2020-09-04 +8;Erklärung Gemeinden Jahr 2020 Margreid.xlsx;Barcatta Lisa;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Margreid;2018-11-07;BRCLSI18S47A952V;Peer Petra;Kurtatsch;2019-09-24;182;2020-06-30;175.75;170.0;135;0;-13.75;332.0;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-06-30 +9;Erklärung Gemeinden Jahr 2020 Margreid.xlsx;Barcatta Lisa;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Margreid;2018-11-07;BRCLSI18S47A952V;Peer Petra;Kurtatsch;2020-07-01;131;2020-11-08;341.5;0.0;0;0;0.0;341.5;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-07-01;2020-11-08 +19;Erklärung Gemeinden Jahr 2020 Marling.xlsx;Ladurner Moritz;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Marling;2017-02-09;LDRMTZ17B09F132D;Leiter Julia;Marling;2019-01-11;267;2020-09-23;606.25;243.75;271;0;130.25;980.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-23 +21;Erklärung Gemeinden Jahr 2020 Marling.xlsx;Matzoll Rene;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Marling;2017-03-30;MTZRNE17C30F132A;Alber Karolina;Meran;2019-08-01;304;2020-10-30;559.0;108.0;166;0;17.0;684.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-10-30 +8;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Agostinetto Matti;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2020-02-09;GSTMTT20B09A952T;Kienzl Martina Rosa;Meran;2020-10-26;67;2020-12-31;63.0;15.0;9;0;0.0;78.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-10-26;2020-12-31 +9;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Agostinetto Levi;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-02-06;GSTLVE17B06A952V;Kienzl Martina Rosa;Meran;2017-10-02;240;2020-08-27;345.75;178.5;197;0;115.5;639.75;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-27 +26;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Burger Karin;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2019-05-20;BRGKRN19E60I729G;Prantl Hildburg;Meran;2020-11-09;53;2020-12-31;62.0;18.0;12;0;0.0;80.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +38;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Ciaramella Lageder Giacomo Clemens;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2019-12-22;CRMGMC19T22F132F;Borarosova Zaneta ;Meran;2020-11-02;60;2020-12-31;156.0;24.0;24;0;0.0;180.0;;;;;;;;;;;;;;;;;;True;;;True;;;;;0;8;0;2020-11-02;2020-12-31 +41;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Costa Yasmina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-05-20;CSTYMN17E60F132Y;Prantl Hildburg;Meran;2020-07-01;80;2020-09-18;241.5;0.0;0;0;0.0;241.5;;;;;;;;;True;;;;;;;;;;;;;;;;;0;0;0;2020-07-01;2020-09-18 +58;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Doliana Mia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2016-12-31;DLNMIA16T71A952X;Theiner Sylvia;Meran;2017-09-18;219;2020-08-06;231.0;175.0;200;0;186.0;592.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-06 +86;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Huber Alexander;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2018-07-27;HBRLND18L27Z102R;Muszala Annekathrin;Meran;2020-02-20;316;2020-12-31;600.5;286.5;281;0;198.5;1085.5;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;0;2020-02-20;2020-12-31 +93;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Massei Damian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-11-29;MSSDMN17S29Z102Y;Schwienbacher Hanna;Lana;2019-09-10;366;2020-12-31;592.5;200.0;193;0;70.0;862.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +96;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Maturilli Anna Maria;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-06-23;MTRNMR17H63F132N;De Arruda Ruth;Meran;2019-05-13;1;2020-01-01;50.0;0.0;0;0;335.0;385.0;;;;;;;;;;;True;True;;;;;;;;;True;;;;;0;0;0;2020-01-01;2020-01-01 +97;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Mazohl Mari;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2018-09-24;MZHMRA18P64F132P;Czuchin Rosa ;Lana;2020-08-23;131;2020-12-31;251.75;20.5;16;0;0.0;272.25;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;0;2020-08-23;2020-12-31 +99;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Niederstaetter Leo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-06-28;NDRLEO17H28F132T;De Arruda Ruth;Meran;2020-11-10;52;2020-12-31;230.5;0.0;35;0;0.0;230.5;;;;;;;;;True;;;;;;;;;;;;;;;;;0;8;0;2020-11-10;2020-12-31 +100;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Niederstaetter Leo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-06-28;NDRLEO17H28F132T;Christanell Elisabeth;Meran;2019-05-02;304;2020-10-30;815.0;241.0;266;0;37.0;1093.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-10-30 +103;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Orlando Amy;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-05-06;RLNMYA17E46F132T;Schwienbacher Hanna;Lana;2020-06-09;114;2020-09-30;138.0;0.0;0;0;0.0;138.0;;;;;;;;;True;;;;;;;;;;;;True;;;;;0;0;0;2020-06-09;2020-09-30 +110;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Perillo Zwink Noah Leon;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-01-15;PRLNLN17A15F132L;Corazza Rosemarie;Meran;2020-07-01;66;2020-09-04;148.5;0.0;0;0;0.0;148.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-07-01;2020-09-04 +111;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Perillo Zwink Noah Leon;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-01-15;PRLNLN17A15F132L;Corazza Rosemarie;Meran;2017-11-02;121;2020-04-30;180.25;203.25;0;0;0.0;383.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-04-30 +114;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Pfattner Jonas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2016-11-25;PFTJNS16S25A952D;Theiner Sylvia;Meran;2018-09-03;255;2020-09-11;696.25;329.25;356;0;203.5;1229.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-11 +115;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Pfattner Jonas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2016-11-25;PFTJNS16S25A952D;Radina Germana ;Meran;2020-08-31;5;2020-09-04;37.0;0.0;0;0;0.0;37.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-08-31;2020-09-04 +121;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Prevedello Timo;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-12-12;PRVTMI17T12F132L;Borarosova Zaneta ;Meran;2018-09-17;366;2020-12-31;1357.0;349.0;384;0;10.5;1716.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +133;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Scano Nicole;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-04-24;SCNNCL17D64F132B;Borarosova Zaneta ;Meran;2018-07-03;274;2020-09-30;389.0;130.0;138;0;-6.5;512.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-30 +143;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Stanzel Amira;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-05-13;STNMRA17E53F132I;Radina Germana ;Meran;2018-07-02;266;2020-09-22;445.0;215.0;182;0;-5.0;655.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-22 +147;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Stragenegg Krieg Paul;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-02-14;STRPLA17B14F132K;Corazza Rosemarie;Meran;2018-02-01;255;2020-09-11;535.0;252.5;274;0;159.0;946.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-11 +154;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Usom Best Daniel;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2017-03-15;SMBDNL17C15A952L;Christanell Elisabeth;Meran;2019-10-21;31;2020-01-31;121.0;0.0;0;0;0.0;121.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-01-01;2020-01-31 +158;Erklärung Gemeinden Jahr 2020 Meran.xlsx;Vassanelli Noah;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Meran;2016-10-13;VSSNHO16R13F132P;Schwalt Kathrin;Meran;2017-07-19;247;2020-09-03;256.0;172.0;182;0;180.0;608.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-03 +9;Erklärung Gemeinden Jahr 2020 Mölten.xlsx;Gruber Emil;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Moelten;2016-12-12;GRBMLE16T12F132N;Duregger Evi;Voeran;2018-02-01;251;2020-09-07;270.5;108.0;115;0;13.5;392.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-07 +10;Erklärung Gemeinden Jahr 2020 Mölten.xlsx;Thaler Leia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Moelten;2019-01-28;THLLEI19A68F132X;Plattner Julia;Terlan;2020-02-17;319;2020-12-31;702.25;201.5;229;0;-13.0;890.75;;;;;;;;;;;;;;;;;True;;;;;;;;;74;8;0;2020-02-17;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Moos In Passeier.xlsx;Gufler Lina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Moos in Passeier;2018-07-17;GFLLNI18L57F132G;Trocker Christine;St. Leonhard i.P.;2020-03-05;63;2020-05-06;0.0;149.0;0;0;0.0;149.0;;;;;;;;;;;;;;True;True;;True;;;;;;;;;0;0;0;2020-03-05;2020-05-06 +11;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Blaas Jakob;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2016-10-29;BLSJKB16R29I729Q;Prantl Stefanie;Kastelbell/Tschars;2020-01-20;12;2020-01-31;48.75;0.0;0;0;0.0;48.75;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-20;2020-01-31 +12;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Blaas Jakob;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2016-10-29;BLSJKB16R29I729Q;Rabensteiner Maria;Naturns;2017-08-10;259;2020-09-15;498.0;117.0;150;0;-89.0;526.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-15 +14;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Burger Linnea;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2018-03-08;BRGLNN18C48I729E;Prantl Stefanie;Kastelbell/Tschars;2020-09-01;122;2020-12-31;296.5;30.0;21;0;0.0;326.5;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;0;2020-09-01;2020-12-31 +15;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Burger Linnea;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2018-03-08;BRGLNN18C48I729E;Blaas Veronika;Kastelbell/Tschars;2020-12-22;1;2020-12-22;5.0;0.0;0;0;0.0;5.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-12-22;2020-12-22 +16;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Burger Linnea;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2018-03-08;BRGLNN18C48I729E;Blaas Veronika;Kastelbell/Tschars;2020-10-23;2;2020-10-24;5.0;0.0;0;0;0.0;5.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-10-23;2020-10-24 +40;Erklärung Gemeinden Jahr 2020 Naturns.xlsx;Schnitzer Lia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Naturns;2018-09-22;SCHLIA18P62F132S;Pixner Silvia;St. Leonhard in Passeier;2020-11-09;53;2020-12-31;92.0;27.5;18;0;0.0;119.5;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;0;2020-11-09;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Natz Schabs.xlsx;Battaglia Mattia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Natz Schabs;2017-09-08;BTTMTT17P08B160L;Salcher Andrea;Mühlbach;2020-02-20;77;2020-05-06;24.75;247.25;0;0;0.0;272.0;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-02-20;2020-05-06 +9;Erklärung Gemeinden Jahr 2020 Olang.xlsx;Winkler Paula;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Olang;2017-10-02;WNKPLA17R42B220L;Oberleiter Maria Magdalena ;Percha;2019-10-23;366;2020-12-31;601.0;175.25;202;0;126.0;902.25;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Partschings.xlsx;Abler Sophie;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Partschins;2016-12-28;BLRSPH16T68F132B;Tappeiner Heidemarie;Partschins;2017-09-01;304;2020-10-30;427.5;169.0;178;0;136.5;733.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-10-30 +9;Erklärung Gemeinden Jahr 2020 Partschings.xlsx;Audino Dennis;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Partschins;2018-03-15;DNADNS18C15F132Y;Rabensteiner Maria;Naturns;2020-03-09;58;2020-05-05;0.0;98.0;0;0;0.0;98.0;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-03-09;2020-05-05 +12;Erklärung Gemeinden Jahr 2020 Partschings.xlsx;Burger Linnea;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Partschins;2018-03-08;BRGLNN18C48I729E;Prantl Stefanie;Kastelbell/Tschars;2019-11-15;244;2020-08-31;471.25;171.75;204;0;30.75;673.75;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-08-31 +23;Erklärung Gemeinden Jahr 2020 Partschings.xlsx;Pircher Rafael Stefan;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Partschins;2017-08-21;PRCRLS17M21I729J;Prantl Stefanie;Kastelbell/Tschars;2020-05-18;110;2020-09-04;322.25;81.0;0;0;0.0;403.25;;;;;;;;;;;;;;True;;;;;;;;;;;;0;0;0;2020-05-18;2020-09-04 +14;Erklärung Gemeinden Jahr 2020 Percha.xlsx;Premstaller Emmi;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Percha;2019-09-25;PRMMME19P65B220I;Auer Petra;Percha;2020-02-28;129;2020-07-05;4.0;122.0;156;0;146.0;272.0;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;0;0;2020-02-28;2020-07-05 +9;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Ellecosta Emely;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2017-11-09;LLCMLY17S49B220J;Leiter Manuela;St.Lorenzen;2020-05-13;233;2020-12-31;487.25;26.25;19;0;63.0;576.5;;;;;;;;;True;True;;;;;True;;;;;;True;;;;;0;8;0;2020-05-13;2020-12-31 +18;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Oberhollenzer Ben;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2017-09-04;BRHBNE17P04B220J;Oberleiter Maria Magdalena ;Percha;2018-09-05;366;2020-12-31;935.0;156.0;247;0;12.0;1103.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +21;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Priller Yara;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2017-04-29;PRLYRA17D69B220C;Winding Helga;Pfalzen;2018-07-02;366;2020-12-31;409.5;125.0;134;0;65.5;600.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +24;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Sevcikova Nadia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2017-01-30;SVCNDA17A70B220F;Volgger Theresia;Vintl;2017-12-11;127;2020-05-06;336.0;275.5;0;0;0.0;611.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-06 +27;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Weger Sophia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2018-04-06;WGRSPH18D46B220D;Rederlechner Angelika;Sand in Taufers;2020-09-04;119;2020-12-31;150.0;18.0;11;0;0.0;168.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;0;2020-09-04;2020-12-31 +28;Erklärung Gemeinden Jahr 2020 Pfalzen.xlsx;Weger Toni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfalzen;2017-02-05;WGRTNO17B05B160N;Winding Helga;Pfalzen;2019-07-01;230;2020-08-17;217.0;100.0;123;0;68.0;385.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-17 +12;Erklärung Gemeinden Jahr 2020 Pfatten.xlsx;Volante Vittorio;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfatten;2017-02-01;VLNVTR17B01A952B;Radicchi Daniela;Pfatten;2018-07-09;127;2020-05-06;228.0;258.0;0;0;0.0;486.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-06 +15;Erklärung Gemeinden Jahr 2020 Pfitsch.xlsx;Whitecotton Leopold Harrison;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Pfitsch;2018-02-20;WHTLLD18B20Z112Z;Oberstaller Agathe;Pfitsch;2020-09-15;108;2020-12-31;174.0;30.0;15;0;0.0;204.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;8;0;2020-09-15;2020-12-31 +9;Erklärung Gemeinden Jahr 2020 Prad a.Stj..xlsx;Ennemoser Ella;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Prad a Stj;2017-01-20;NNMLLE17A60A952M;Weisenhorn Annamaria;Mals i.V.;2019-07-15;121;2020-04-30;152.5;174.0;0;0;0.0;326.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-04-30 +16;Erklärung Gemeinden Jahr 2020 Rasen-Antholz.xlsx;Taschler Anton;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Rasen/Antholz;2017-07-08;TSCNTN17L08B220M;Oberleiter Maria Magdalena ;Percha;2018-06-25;366;2020-12-31;780.5;232.0;248;0;94.75;1107.25;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +8;Erklärung Gemeinden Jahr 2020 Ratschings.xlsx;Fiechter Emil;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ratschings;2017-01-12;FCHMLE17A12B160W;Thaler Petra;Ratschings;2020-01-03;251;2020-09-09;272.0;124.5;146;0;101.5;498.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-03;2020-09-09 +11;Erklärung Gemeinden Jahr 2020 Ratschings.xlsx;Pillon Luna;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ratschings;2019-03-01;PLLLNU19C41B160R;Thaler Petra;Ratschings;2020-03-23;284;2020-12-31;544.5;7.0;20;0;25.0;576.5;;;;;;;;;;True;;;;;True;;;;;;;;;;;0;8;2;2020-03-23;2020-12-31 +13;Erklärung Gemeinden Jahr 2020 Ratschings.xlsx;Santer Zoey;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ratschings;2019-05-11;SNTZYO19E51B160D;Thaler Petra;Ratschings;2020-03-16;291;2020-12-31;521.75;20.75;19;0;23.75;566.25;;;;;;;;;;True;;;;;True;;;;;;;;;;;0;8;2;2020-03-16;2020-12-31 +15;Erklärung Gemeinden Jahr 2020 Ratschings.xlsx;Walter Moritz;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ratschings;2016-08-02;WLTMTZ16M02M067H;Oberstaller Agathe;Pfitsch;2017-12-01;185;2020-07-03;470.75;268.5;315;0;49.0;788.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-07-03 +9;Erklärung Gemeinden Jahr 2020 Riffian.xlsx;Gruber Karolina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Riffian;2017-01-30;GRBKLN17A70F132K;Trientbacher Margit;Riffian;2018-03-01;248;2020-09-04;429.75;193.5;195;0;33.25;656.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-04 +12;Erklärung Gemeinden Jahr 2020 Riffian.xlsx;Pichler Simon;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Riffian;2019-07-15;PCHSMN19L15F132H;Trientbacher Margit;Riffian;2020-03-03;304;2020-12-31;360.5;168.0;198;0;207.25;735.75;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;8;0;2020-03-03;2020-12-31 +10;Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx;Ausserhofer Matthias;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sand in Taufers;2017-11-09;SSRMTH17S09B220Q;Rederlechner Angelika;Sand in Taufers;2019-05-06;366;2020-12-31;394.0;116.25;118;0;20.25;530.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +11;Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx;Eder Bruno;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sand in Taufers;2019-06-09;DREBRN19H09B220H;Berger Michaela;Sand in Taufers;2020-03-04;303;2020-12-31;448.5;113.0;149;0;-10.5;551.0;;;;;;;;;;;;;;;;;True;;;;;;;;;74;8;0;2020-03-04;2020-12-31 +12;Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx;Ellecosta Emely;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sand in Taufers;2017-11-09;LLCMLY17S49B220J;Leiter Manuela;St.Lorenzen;2019-05-06;133;2020-05-12;135.0;157.5;0;0;0.0;292.5;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-01-01;2020-05-12 +17;Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx;Niederkofler Josef;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sand in Taufers;2017-01-20;NDRJSF17A20B220Z;Rederlechner Angelika;Sand in Taufers;2018-11-05;212;2020-07-30;232.0;140.0;155;0;72.0;444.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-07-30 +21;Erklärung Gemeinden Jahr 2020 Sand in Taufers.xlsx;Weger Sophia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sand in Taufers;2018-04-06;WGRSPH18D46B220D;Rederlechner Angelika;Sand in Taufers;2019-09-09;247;2020-09-03;260.0;104.0;118;0;32.0;396.0;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-09-03 +10;Erklärung Gemeinden Jahr 2020 Sarntal.xlsx;Desaler Viktoria;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sarntal;2017-01-11;DSLVTR17A51A952V;Gufler Petra;Sarntal;2018-12-03;163;2020-06-11;242.75;189.0;216;0;45.0;476.75;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-06-11 +26;Erklärung Gemeinden Jahr 2020 Sarntal.xlsx;Thaler Nils;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sarntal;2017-11-11;THLNLS17S11A952H;Frenzel Karina;Sarntal;2020-03-23;39;2020-04-30;0.0;57.0;0;0;0.0;57.0;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-03-23;2020-04-30 +11;Erklärung Gemeinden Jahr 2020 Schenna.xlsx;Illmer Rafael;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schenna;2019-02-10;LLMRFL19B10F132U;Mittelberger Maria;Schenna;2020-03-16;291;2020-12-31;443.5;139.0;20;0;164.0;746.5;;;;;;;;;;True;;;;;True;;;;;;;;;;;0;8;0;2020-03-16;2020-12-31 +16;Erklärung Gemeinden Jahr 2020 Schenna.xlsx;Pföstl Philipp;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schenna;2017-02-08;PFSPLP17B08F132P;Unterholzner Tanja;Schenna;2018-02-05;273;2020-09-29;394.5;129.0;147;0;19.5;543.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-29 +8;Erklärung Gemeinden Jahr 2020 Schlanders.xlsx;Doda Denis;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schlanders;2017-07-05;DDODNS17L05I729E;Kaserer Monika;Schlanders;2018-03-20;262;2020-09-18;528.0;280.0;286;0;205.5;1013.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-18 +21;Erklärung Gemeinden Jahr 2020 Schlanders.xlsx;Thoman Aimar Amalia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schlanders;2017-12-29;THMMLA17T69I729V;Kaserer Monika;Schlanders;2018-08-07;260;2020-09-16;471.25;227.5;241;0;148.5;847.25;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-16 +22;Erklärung Gemeinden Jahr 2020 Schlanders.xlsx;Trafoier Alex;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schlanders;2017-11-27;TRFLXA17S27I729K;Stecher Romina;Schlanders;2019-04-01;261;2020-09-17;425.0;170.0;143;0;-90.0;505.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-17 +12;Erklärung Gemeinden Jahr 2020 Schnals.xlsx;Gorfer Florian;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schnals;2018-05-23;GRFFRN18E23I729P;Graiss Lisa;Schnals;2020-05-04;179;2020-10-29;249.75;12.0;0;0;0.0;261.75;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-05-04;2020-10-29 +15;Erklärung Gemeinden Jahr 2020 Schnals.xlsx;Woerndle Paul;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Schnals;2017-12-13;WRNPLA17T13I729Z;Graiss Lisa;Schnals;2020-11-02;60;2020-12-31;62.0;18.0;13;0;0.0;80.0;;;;;;;;;True;;;;;;;;;True;;;;;;;;0;8;2;2020-11-02;2020-12-31 +11;Erklärung Gemeinden Jahr 2020 St. Leonhard in Passeier.xlsx;Gumpold Marius;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Leonhard in Passeier;2017-08-28;GMPMRS17M28F132X;Trocker Christine;St. Leonhard in P.;2020-12-01;31;2020-12-31;69.0;0.0;0;0;0.0;69.0;;;;;;;;;True;;;;;;;;;;;;;;;;;0;0;0;2020-12-01;2020-12-31 +13;Erklärung Gemeinden Jahr 2020 St. Lorenzen.xlsx;Huber David;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Lorenzen;2016-11-18;HBRDVD16S18B220L;Leiter Manuela;St.Lorenzen;2018-09-17;244;2020-08-31;418.75;143.5;170;0;-0.5;561.75;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-31 +16;Erklärung Gemeinden Jahr 2020 St. Lorenzen.xlsx;Moosbrugger Theresa;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Lorenzen;2017-02-02;MSBTRS17B42Z102X;Leiter Manuela;St.Lorenzen;2019-03-11;219;2020-08-06;200.75;104.0;120;0;51.5;356.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-06 +13;Erklärung Gemeinden Jahr 2020 St. Martin In Passeier.xlsx;Kofler Andreas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Martin in Passeier;2017-11-23;KFLNRS17S23F132N;Schweigl Simone;St. Martin In P.;2020-09-09;114;2020-12-31;200.0;13.75;15;0;0.0;213.75;;;;;;;;;True;;;;;;;;;;;;;;;;;0;8;0;2020-09-09;2020-12-31 +11;Erklärung Gemeinden Jahr 2020 St. Pankraz Ulten.xlsx;Matzoll Simon;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Pankraz Ulten;2016-12-01;MTZSMN16T01F132M;Zöschg Gertrud;St. Pankraz Ulten;2019-08-26;52;2020-02-21;122.5;0.0;0;0;0.0;122.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-02-21 +19;Erklärung Gemeinden Jahr 2020 St. Pankraz Ulten.xlsx;Schwienbacher Ida;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;St. Pankraz Ulten;2019-08-08;SCHDIA19M48F132M;Zöschg Gertrud;St. Pankraz Ulten;2020-01-29;106;2020-05-13;31.0;119.0;0;0;71.0;221.0;;;;;;;;;;;True;;;;;;;;;;True;;;;;0;0;0;2020-01-29;2020-05-13 +15;Erklärung Gemeinden Jahr 2020 Sterzing.xlsx;Whitecotton Leopold Harrison;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Sterzing;2018-02-20;WHTLLD18B20Z112Z;Oberstaller Agathe;Pfitsch;2019-09-17;90;2020-03-30;116.0;44.0;0;0;0.0;160.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-01-01;2020-03-30 +10;Erklärung Gemeinden Jahr 2020 Taufers im Münstertal.xlsx;Imonsili Mercy;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Taufers i. M.;2018-04-23;MNSMCY18D63A952N;Oswald Maria Pia;Mals i.V.;2020-05-18;35;2020-06-21;58.0;0.0;0;0;0.0;58.0;;;;;;;;;;;;;;;;;;;;;True;;;;;0;0;0;2020-05-18;2020-06-21 +11;Erklärung Gemeinden Jahr 2020 Taufers im Münstertal.xlsx;Malloth Daniel;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Taufers i. M.;2017-07-10;MLLDNL17L10I729Y;Weisenhorn Annamaria;Mals i.V.;2020-02-13;184;2020-08-14;170.0;168.5;189;0;131.5;470.0;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;0;0;2020-02-13;2020-08-14 +9;Erklärung Gemeinden Jahr 2020 Tiers.xlsx;Lunger Ida;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tiers;2017-11-11;LNGDIA17S51A952F;Lunger Alexandra;Tiers;2018-09-03;268;2020-09-24;300.0;117.0;128;0;49.5;466.5;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-24 +11;Erklärung Gemeinden Jahr 2020 Tiers.xlsx;Mentzel Katharina;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tiers;2017-01-15;MNTKHR17A55A952Q;Lunger Alexandra;Tiers;2019-02-14;127;2020-05-06;189.5;202.5;0;0;0.0;392.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-06 +14;Erklärung Gemeinden Jahr 2020 Tiers.xlsx;Rieder Isabel;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tiers;2016-08-10;RDRSBL16M50A952F;Lunger Alexandra;Tiers;2018-11-05;17;2020-01-17;32.5;0.0;0;0;0.0;32.5;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-01-17 +10;Erklärung Gemeinden Jahr 2020 Tirol.xlsx;Prantl Rosa;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tirol;2018-02-09;PRNRSO18B49F132Z;Schwalt Kathrin;Meran;2020-03-03;65;2020-05-06;6.25;112.5;0;0;0.0;118.75;;;;;;;;;;;;;;;;;True;;;;;;;;;0;0;0;2020-03-03;2020-05-06 +10;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Niederstaetter Leni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2016-12-19;NDRLNE16T59A952N;Wolf Alexandra;Tscherms;2019-05-02;154;2020-06-02;87.5;108.0;113;0;40.0;235.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-06-02 +11;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Niederstaetter Leni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2016-12-19;NDRLNE16T59A952N;Wolf Alexandra;Tscherms;2020-06-03;93;2020-09-03;113.5;0.0;0;0;24.5;138.0;;;;;;;;True;;True;;;;;;;;;;;;;;;;0;0;0;2020-06-03;2020-09-03 +12;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Niederstaetter Toni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2016-12-19;NDRTNO16T19A952B;Wolf Alexandra;Tscherms;2019-05-02;154;2020-06-02;87.5;108.0;113;0;40.0;235.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-06-02 +13;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Niederstaetter Toni;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2016-12-19;NDRTNO16T19A952B;Wolf Alexandra;Tscherms;2020-06-03;93;2020-09-03;113.5;0.0;0;0;24.5;138.0;;;;;;;;True;;True;;;;;;;;;;;;;;;;0;0;0;2020-06-03;2020-09-03 +14;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Pircher Paul;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2016-11-29;PRCPLA16S29F132U;Wolf Alexandra;Tscherms;2017-08-07;211;2020-07-29;301.5;204.0;233;0;160.0;665.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-07-29 +15;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Santner Lenz;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2018-01-30;SNTLNZ18A30F132R;Ladurner Irene;Marling;2019-02-18;316;2020-11-11;379.0;164.5;162;0;151.0;694.5;;;;;;;;;;;;;;;;;;;;;True;;;;;74;0;0;2020-01-01;2020-11-11 +16;Erklärung Gemeinden Jahr 2020 Tscherms.xlsx;Scheibenhoffer Alexander;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tscherms;2017-02-12;SCHLND17B12F132N;Hofer Carina;Marling;2020-02-11;218;2020-09-15;350.5;210.0;190;0;0.0;560.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-02-11;2020-09-15 +9;Erklärung Gemeinden Jahr 2020 Tramin.xlsx;Frei Juri;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tramin;2018-05-29;FREJRU18E29A952R;Peer Petra;Kurtatsch;2020-03-10;57;2020-05-05;0.0;90.0;0;0;0.0;90.0;;;;;;;;;;;;;;True;True;;;;;;;;;;;0;0;0;2020-03-10;2020-05-05 +11;Erklärung Gemeinden Jahr 2020 Tramin.xlsx;Kajana Mia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Tramin;2018-08-03;KJNMIA18M43A952A;Ambach Maria;Eppan;2019-08-06;138;2020-05-17;99.5;144.75;0;0;66.25;310.5;;;;;;;;;;;True;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-05-17 +9;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Gamper Klaus;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2016-12-18;GMPKLS16T18F132L;Zöschg Rita ;Ulten;2020-02-18;78;2020-05-05;25.5;256.0;0;0;0.0;281.5;;;;;;;;True;;;;;;;;;True;;;;;;;;;0;0;0;2020-02-18;2020-05-05 +11;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Gamper Martha;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2019-04-07;GMPMTH19D47F132J;Zöschg Rita ;Ulten;2020-02-18;210;2020-09-14;20.5;256.0;232;0;382.0;658.5;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;0;0;2020-02-18;2020-09-14 +15;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Karlegger Svenja Heidrun;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2018-09-09;KRLSNJ18P49I729Y;Unterholzner Vera;Ulten;2020-03-02;227;2020-10-14;211.25;102.0;123;0;65.25;378.5;;;;;;;;;;;;;;;;True;True;;;;;;;;;74;0;0;2020-03-02;2020-10-14 +17;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Pircher Hannes;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2017-03-08;PRCHNS17C08F132K;Zöschg Rita ;Ulten;2019-05-15;366;2020-12-31;833.0;156.0;213;0;-38.0;951.0;;;;;;;;;True;;;;;;;;;;;;;;;;;74;8;0;2020-01-01;2020-12-31 +24;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Schwienbacher Ida;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2019-08-08;SCHDIA19M48F132M;Zöschg Gertrud;St. Pankraz Ulten;2020-05-14;232;2020-12-31;314.5;19.0;7;0;-118.0;215.5;;;;;;;;;;;;;;;True;;;;;;True;;;;;0;8;0;2020-05-14;2020-12-31 +25;Erklärung Gemeinden Jahr 2020 Ulten.xlsx;Trafojer Jakob;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Ulten;2016-11-22;TRFJKB16S22F132Q;Zöschg Rita ;Ulten;2019-06-06;247;2020-09-03;395.5;129.5;144;0;-44.0;481.0;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-03 +11;Erklärung Gemeinden Jahr 2020 Villnöss.xlsx;Mayer Fabienne;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Villnöss;2017-07-27;MYRFNN17L67B160A;Aukenthaler Roswitha;Villnöss;2019-05-02;261;2020-09-17;425.75;122.5;150;0;-18.5;529.75;;;;;;;;;True;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-17 +17;Erklärung Gemeinden Jahr 2020 Vintl.xlsx;Mor Nadyn;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Vintl;2016-09-25;MRONYN16P65B160C;Huber Barbara;Vintl;2018-08-24;194;2020-07-12;127.5;109.5;125;0;92.25;329.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-07-12 +18;Erklärung Gemeinden Jahr 2020 Vintl.xlsx;Mor Nadyn;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Vintl;2016-09-25;MRONYN16P65B160C;Huber Barbara;Vintl;2020-07-13;60;2020-09-10;128.25;0.0;0;0;0.0;128.25;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-07-13;2020-09-10 +20;Erklärung Gemeinden Jahr 2020 Vintl.xlsx;Ploner Simon;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Vintl;2017-01-18;PLNSMN17A18B220Q;Volgger Theresia;Vintl;2018-05-07;241;2020-08-28;392.0;104.0;157;0;16.5;512.5;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-08-28 +12;Erklärung Gemeinden Jahr 2020 Völs am Schlern.xlsx;Villgrattner Jonas;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Völs am Schlern;2017-01-09;VLLJNS17A09B160F;Lunger Alexandra;Tiers;2020-08-13;30;2020-09-11;76.0;0.0;0;0;0.0;76.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-08-13;2020-09-11 +9;Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx;Dejori Pia;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Welschnofen;2017-01-27;DJRPIA17A67A952Q;Kompatscher Sarah;Welschnofen;2018-11-05;261;2020-09-17;308.25;117.0;136;0;56.0;481.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-17 +12;Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx;Kircher Lena;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Welschnofen;2017-02-13;KRCLNE17B53B160I;Kompatscher Sarah;Welschnofen;2018-06-26;258;2020-09-14;989.75;280.5;342;0;-77.0;1193.25;;;;;;;;True;;;;;;;;;;;;;;;;;;74;0;0;2020-01-01;2020-09-14 +13;Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx;Kohler Mali;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Welschnofen;2017-01-31;KHLMLA17A71A952X;Kompatscher Sarah;Welschnofen;2018-12-17;101;2020-04-10;129.0;77.0;0;0;0.0;206.0;;;;;;;;True;;;;;;;;;;;;;;;;;;0;0;0;2020-01-01;2020-04-10 +19;Erklärung Gemeinden Jahr 2020 Welschnofen.xlsx;Vieider Stina Marie;Sozialgenossenschaft Mit Bäuerinnen Lernen-Wachsen-Leben;Welschnofen;2018-08-16;VDRSNM18M56B160V;Kompatscher Sarah;Welschnofen;2020-10-27;66;2020-12-31;72.0;12.0;12;0;0.0;84.0;;;;;;;;;;;;;;;;;;True;;;;;;;;0;8;2;2020-10-27;2020-12-31 diff --git a/pages/test2.csv b/pages/test2.csv new file mode 100644 index 0000000000000000000000000000000000000000..44e67afa8c117f9634bc50d705e3c229bf675ffd --- /dev/null +++ b/pages/test2.csv @@ -0,0 +1,105 @@ +,filename,Cognome e nome bambino,Ente,Comune,Data di nascita,Codice fiscale,Assistente domiciliare all'infanzia,Comune di residenza assistente domiciliare all'infanzia,Data inizio contratto (o data inizio assistenza se diversa),GiorniAssistenzaAnnoRiferimento,"Data fine contratto +(o data fine assistenza se diversa) *","Ore di assistenza + ai sensi della delibera +n. 666/2019","Ore contrattualizzate non erogate +ai sensi della delibera +n. 543_1025/2020",massimo543,"Ore contrattualizzate non erogate +ai sensi della delibera +n. 733/2020","Ore contrattualizzate non erogate +nella fase 2 (finanziamento compensativo)",Ore totali rendicontate per il 2020,errCodFisc1,errCodFisc2,errAgeChild,errInizioMinoreFine,errErrorePresenza,errErroreDati543,errFineAssistenzaMax4Anni,errKindergarten_1,errKindergarten_2,errErroreFinanziamentoCompensativo,errErroreFinanziamentoCompensativo2,errErroreCovid,errErroreCovid2,errErroreCovid3,errErroreCovid4,errFehlerEingewöhnung,errFehlerEingewöhnung543Lockdown,errFehlerEingewöhnung543Notbetreuung,errGesamtstundenVertragszeitraum,errSuperatoOreMassime1920,errBambinoInPiuComuni,errPresentiAnnotazioni,errOreRendicontateZero,errSommaOre,errMassimoFC,gg1,gg2,gg3,inizioNorm,fineNorm +9,Erklärung_Gemeinde_Brixen_2020.xlsx,ALBERTI VICKY,Sozialgenossenschaft Tagesmütter - Gen.,Brixen,2017-11-03,LBRVKY17S43B160U,PUNER PAULA,Vahrn/Varna,2018-09-03,366,2021-09-03,884.25,234.0,256,0,24.5,1142.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +23,Erklärung_Gemeinde_Brixen_2020.xlsx,NITZ MIA,Sozialgenossenschaft Tagesmütter - Gen.,Brixen,2017-10-06,NTZMIA17R46B160F,PUNER PAULA,Vahrn/Varna,2018-09-24,366,2021-08-27,868.5,296.0,267,0,29.0,1193.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +23,Erklärung_Gemeinde_Bruneck_2020.xlsx,SANTON PHILIPP,Sozialgenossenschaft Tagesmütter - Gen.,Bruneck,2019-01-31,SNTPLP19A31B220R,FEICHTER ELISABETH,Bruneck/Brunico,2020-04-06,270,2021-01-13,391.5,0.0,11,0,0.0,391.5,,,,,,,,,,,,,,,True,,,,,,,,,,,0,8,0,2020-04-06,2020-12-31 +25,Erklärung_Gemeinde_Bruneck_2020.xlsx,TOLLOI MATTHAEUS,Sozialgenossenschaft Tagesmütter - Gen.,Bruneck,2017-02-28,TLLMTH17B28B220V,TAFERNER PETRA,Bruneck/Brunico,2018-01-15,220,2020-08-07,354.25,170.0,195,0,55.5,579.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-07 +15,Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx,FABI MARIE (TM),Sozialgenossenschaft Tagesmütter - Gen.,Eppan a.d. Weinstr.,2016-12-20,FBAMRA16T60F132X,LANTHALER UTE,Eppan a.d. Weinstr./Appiano s.s.d.v.,2017-11-27,35,2020-02-04,63.0,0.0,0,0,0.0,63.0,,,,,,,,True,,,,,,,,,,,,,,True,,,,0,0,0,2020-01-01,2020-02-04 +19,Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx,FRAU AARON,Sozialgenossenschaft Tagesmütter - Gen.,Eppan a.d. Weinstr.,2018-07-05,FRARNA18L05A952U,LANTHALER UTE,Eppan a.d. Weinstr./Appiano s.s.d.v.,2018-10-01,366,2021-06-25,520.0,150.0,174,0,89.0,759.0,,,True,,,,,,,,,,,,,,,,,,,,,,,74,8,2,2020-01-01,2020-12-31 +30,Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx,KOESSLER JOHAN,Sozialgenossenschaft Tagesmütter - Gen.,Eppan a.d. Weinstr.,2019-01-02,KSSJHN19A02A952N,KIER CLAUDIA,Eppan a.d. Weinstr./Appiano s.s.d.v.,2019-04-01,366,2022-08-26,513.0,173.0,185,0,122.0,808.0,,,True,,,,,,,,,,,,,,,,,,,,,,,74,8,2,2020-01-01,2020-12-31 +32,Erklärung_Gemeinde_Eppan a.d. Weinstr._2020.xlsx,MADEDDU DAVIS,Sozialgenossenschaft Tagesmütter - Gen.,Eppan a.d. Weinstr.,2017-01-08,MDDDVS17A08A952N,PLATTNER HELENE,Eppan a.d. Weinstr./Appiano s.s.d.v.,2018-01-08,178,2020-06-26,150.75,192.0,182,0,97.0,439.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-26 +8,Erklärung_Gemeinde_Freienfeld_2020.xlsx,TRATTER JOHANNES,Sozialgenossenschaft Tagesmütter - Gen.,Freienfeld,2018-08-26,TRTJNN18M26B160I,FÜRLER VERONIKA,Freienfeld/Campo di Trens,2019-05-06,225,2020-08-12,837.0,450.0,470,0,144.0,1431.0,,,,,,,,,,,,,,,,,,,True,True,True,,,,,74,0,0,2020-01-01,2020-08-12 +9,Erklärung_Gemeinde_Freienfeld_2020.xlsx,TRATTER PIA,Sozialgenossenschaft Tagesmütter - Gen.,Freienfeld,2017-06-03,TRTPIA17H43B160S,FÜRLER VERONIKA,Freienfeld/Campo di Trens,2018-01-29,225,2020-08-12,819.0,400.0,424,0,70.0,1289.0,,,,,,,,,,,,,,,,,,,True,,,,,,,74,0,0,2020-01-01,2020-08-12 +9,Erklärung_Gemeinde_Gargazon_2020.xlsx,MAIR FINN /,Sozialgenossenschaft Tagesmütter - Gen.,Gargazon,2019-05-01,MRAFNN19E01F132B,VARHANIKOVA LENKA,Terlan/Terlano,2020-02-17,319,2022-04-29,865.5,0.0,122,0,-388.5,477.0,,,,,,,,,,,,,,,,,,,,,True,True,,,,74,8,0,2020-02-17,2020-12-31 +9,Erklärung_Gemeinde_Klausen_2020.xlsx,KOFLER PAULI,Sozialgenossenschaft Tagesmütter - Gen.,Klausen,2019-06-24,KFLPLA19H24B220Y,PEINTNER CAROLIN,Rasen-Antholz/Rasun Anterselva,2020-09-14,8,2020-09-21,8.0,0.0,0,0,0.0,8.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-09-14,2020-09-21 +8,Erklärung_Gemeinde_Laas_2020.xlsx,HOCHKOFLER NADINE,Sozialgenossenschaft Tagesmütter - Gen.,Laas,2017-08-13,HCHNDN17M53I729Y,GURSCHLER ANDREA,Schluderns/Sluderno,2020-01-15,224,2020-08-25,113.0,200.0,188,0,256.0,569.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-15,2020-08-25 +9,Erklärung_Gemeinde_Lana_2020.xlsx,BARBAGALLO GIADA,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-07-09,BRBGDI17L49A952B,LAGEDER JOHANNA,Lana/Lana,2019-10-21,260,2020-09-16,469.25,210.0,200,0,24.0,703.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-16 +11,Erklärung_Gemeinde_Lana_2020.xlsx,BREDENHOELLER LILLY SOPHIE /,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2018-08-26,BRDLLY18M66F132T,MARINI ANNARITA,Meran/Merano,2020-11-09,53,2021-08-27,149.5,0.0,22,0,0.0,149.5,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,8,0,2020-11-09,2020-12-31 +14,Erklärung_Gemeinde_Lana_2020.xlsx,DE ZORDO LISA MARIE,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-02-24,DZRLMR17B64A952J,KRÖSS WALTRAUD,Lana/Lana,2018-08-27,262,2020-09-18,479.75,150.0,161,0,-57.25,572.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +17,Erklärung_Gemeinde_Lana_2020.xlsx,ERB VIKTORIA,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-02-03,RBEVTR17B43F132X,LAIMER HELGA,Lana/Lana,2018-10-01,182,2020-06-30,144.0,374.0,210,0,0.0,518.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-30 +19,Erklärung_Gemeinde_Lana_2020.xlsx,FREI KATHARINA *,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2019-08-25,FREKHR19M65F132M,GIOVANAZZI ANJA,Lana/Lana,2020-09-14,109,2022-09-02,188.5,18.0,15,0,0.0,206.5,,,,,,,,,,,,,,,,,,,,,,True,,,,0,8,0,2020-09-14,2020-12-31 +20,Erklärung_Gemeinde_Lana_2020.xlsx,GALANTIN ILVY MARIE,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-01-19,GLNLYM17A59F132K,LAIMER HELGA,Lana/Lana,2018-01-22,31,2020-01-31,77.5,0.0,0,0,0.0,77.5,,,,,,,,True,,,,,,,,,,,,,,,,,,0,0,0,2020-01-01,2020-01-31 +23,Erklärung_Gemeinde_Lana_2020.xlsx,GASSER LARA,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-02-08,GSSLRA17B48F132D,LEITNER ANNELIES,Lana/Lana,2017-12-05,182,2020-06-30,190.0,380.0,231,0,0.0,570.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-30 +27,Erklärung_Gemeinde_Lana_2020.xlsx,GURNDIN LENA,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2018-07-04,GRNLNE18L44F132V,MITTERHOFER MARTINA,Lana/Lana,2020-11-02,60,2021-10-01,130.5,16.5,19,0,0.0,147.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-02,2020-12-31 +35,Erklärung_Gemeinde_Lana_2020.xlsx,MAIRHOFER MARIE,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-10-05,MRHMRA17R45F132N,LAGEDER JOHANNA,Lana/Lana,2019-10-07,366,2021-07-31,0.0,150.0,75,0,187.5,337.5,,,,,,,,,True,,,,,,,,,,,,True,,,,,74,8,0,2020-01-01,2020-12-31 +38,Erklärung_Gemeinde_Lana_2020.xlsx,PARIS MARIE,Sozialgenossenschaft Tagesmütter - Gen.,Lana,2017-05-13,PRSMRA17E53F132P,MITTERHOFER MARTINA,Lana/Lana,2018-05-14,262,2020-09-18,459.5,289.0,211,0,-0.75,747.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +12,Erklärung_Gemeinde_Leifers_2020.xlsx,BERTACCHE SAMUEL,Sozialgenossenschaft Tagesmütter - Gen.,Leifers,2017-09-23,BRTSML17P23A952Y,BONADIO CONCETTA,Bozen/Bolzano,2020-02-10,201,2020-08-28,48.0,144.0,118,0,129.0,321.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-02-10,2020-08-28 +14,Erklärung_Gemeinde_Leifers_2020.xlsx,CABULA LEONARDO,Sozialgenossenschaft Tagesmütter - Gen.,Leifers,2017-07-24,CBLLRD17L24A952H,PUFF CHRISTINA,Leifers/Laives,2018-08-20,27,2020-01-27,90.0,0.0,0,0,0.0,90.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-01-27 +9,Erklärung_Gemeinde_Mals_2020.xlsx,GAISER DARIA,Sozialgenossenschaft Tagesmütter - Gen.,Mals,2017-07-21,GSRDRA17L61I729N,GURSCHLER ANDREA,Schluderns/Sluderno,2019-01-21,290,2020-10-16,294.0,120.0,104,0,-6.0,408.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-10-16 +11,Erklärung_Gemeinde_Mals_2020.xlsx,VILL LIAM,Sozialgenossenschaft Tagesmütter - Gen.,Mals,2018-05-15,VLLLMI18E15I729L,UNTERTHURNER CARMEN,Schlanders/Silandro,2020-11-04,58,2021-08-27,76.5,0.0,10,0,0.0,76.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,8,0,2020-11-04,2020-12-31 +14,Erklärung_Gemeinde_Mölten_2020.xlsx,PLONER LEONIE /,Sozialgenossenschaft Tagesmütter - Gen.,Mölten,2020-04-05,PLNLNE20D45A952Z,INNERHOFER MARTHA,Mölten/Meltina,2020-11-13,49,2023-09-22,79.25,0.0,12,0,0.0,79.25,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,8,0,2020-11-13,2020-12-31 +15,Erklärung_Gemeinde_Mölten_2020.xlsx,PLONER MARIAN /,Sozialgenossenschaft Tagesmütter - Gen.,Mölten,2018-07-26,PLNMRN18L26B160A,INNERHOFER MARTHA,Mölten/Meltina,2020-11-13,49,2021-08-27,79.25,0.0,12,0,0.0,79.25,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,8,0,2020-11-13,2020-12-31 +14,Erklärung_Gemeinde_Meran_2020.xlsx,BIASI PAUL,Sozialgenossenschaft Tagesmütter - Gen.,Meran,2018-10-31,BSIPLA18R31A952C,SCHEITLER SABINE ISABELLA,Meran/Merano,2020-03-02,305,2021-04-02,359.75,168.0,156,0,55.5,583.25,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +18,Erklärung_Gemeinde_Meran_2020.xlsx,BREDENHOELLER LILLY SOPHIE,Sozialgenossenschaft Tagesmütter - Gen.,Meran,2018-08-26,BRDLLY18M66F132T,MARINI ANNARITA,Meran/Merano,2019-09-16,313,2020-11-08,291.75,136.0,130,0,125.0,552.75,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-11-08 +28,Erklärung_Gemeinde_Meran_2020.xlsx,INNERHOFER SOPHIA,Sozialgenossenschaft Tagesmütter - Gen.,Meran,2017-02-24,NNRSPH17B64F132A,MARINI ANNARITA,Meran/Merano,2018-08-20,241,2020-08-28,626.5,300.0,286,0,7.75,934.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +29,Erklärung_Gemeinde_Meran_2020.xlsx,KLOTZNER LAHNER ELIAS,Sozialgenossenschaft Tagesmütter - Gen.,Meran,2017-09-14,KLTLSE17P14F132J,MARINI ANNARITA,Meran/Merano,2018-03-19,269,2020-09-25,639.0,300.0,278,0,73.5,1012.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-25 +43,Erklärung_Gemeinde_Meran_2020.xlsx,WIDMANN NIKLAS JAN,Sozialgenossenschaft Tagesmütter - Gen.,Meran,2019-03-11,WDMNLS19C11F132C,MARINI ANNARITA,Meran/Merano,2020-11-16,46,2022-08-26,72.5,27.0,17,0,0.0,99.5,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-16,2020-12-31 +10,Erklärung_Gemeinde_Montan_2020.xlsx,KAUFMANN SAMUEL,Sozialgenossenschaft Tagesmütter - Gen.,Montan,2017-10-13,KFMSML17R13A952W,FLENGER ALEXANDRA,Montan/Montagna,2018-08-20,262,2020-09-18,409.0,228.0,185,0,19.75,656.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +13,Erklärung_Gemeinde_Montan_2020.xlsx,TERLETH LUKAS,Sozialgenossenschaft Tagesmütter - Gen.,Montan,2017-10-26,TRLLKS17R26A952Z,FLENGER ALEXANDRA,Montan/Montagna,2019-09-09,262,2020-09-18,514.75,271.0,216,0,-18.75,767.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +14,Erklärung_Gemeinde_Montan_2020.xlsx,THALER DOMINIK,Sozialgenossenschaft Tagesmütter - Gen.,Montan,2017-11-13,THLDNK17S13F132U,PICHLER ELISABETH,Montan/Montagna,2018-05-28,262,2020-09-18,333.5,271.0,202,0,113.5,718.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +8,Erklärung_Gemeinde_Nals_2020.xlsx,MAIR FINN,Sozialgenossenschaft Tagesmütter - Gen.,Nals,2019-05-01,MRAFNN19E01F132B,VARHANIKOVA LENKA,Terlan/Terlano,2020-02-17,319,2022-04-29,53.0,165.0,118,0,244.0,462.0,,,,,,,,,,,,,,,,True,True,,,,True,,,,,74,8,0,2020-02-17,2020-12-31 +8,Erklärung_Gemeinde_Natz-Schabs_2020.xlsx,FILO JAKOB,Sozialgenossenschaft Tagesmütter - Gen.,Natz-Schabs,2017-01-26,FLIJKB17A26B160K,KALTENHAUSER ADELHEID,Brixen/Bressanone,2019-08-12,171,2020-06-19,209.0,358.0,353,0,250.0,817.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-19 +8,Erklärung_Gemeinde_Niederdorf_2020.xlsx,STEINWANDTER FELIX,Sozialgenossenschaft Tagesmütter - Gen.,Niederdorf,2017-12-10,STNFLX17T10B220L,KARGRUBER AGNES,Welsberg/Monguelfo,2019-09-30,366,2020-12-31,623.75,209.0,189,0,39.0,847.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +9,Erklärung_Gemeinde_Niederdorf_2020.xlsx,THOMASER NOEMI,Sozialgenossenschaft Tagesmütter - Gen.,Niederdorf,2016-12-06,THMNMO16T46B220C,KARGRUBER AGNES,Welsberg/Monguelfo,2018-08-20,241,2020-08-28,454.5,226.0,214,0,18.5,699.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +8,Erklärung_Gemeinde_Pfalzen_2020.xlsx,HEISS ANTON,Sozialgenossenschaft Tagesmütter - Gen.,Pfalzen,2017-12-11,HSSNTN17T11B220O,MAIRHOFER HEIDRUN,Bruneck/Brunico,2018-09-17,366,2021-08-27,745.0,230.0,216,0,26.0,966.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +9,Erklärung_Gemeinde_Pfalzen_2020.xlsx,HEISS MICHAEL,Sozialgenossenschaft Tagesmütter - Gen.,Pfalzen,2017-12-11,HSSMHL17T11B220O,MAIRHOFER HEIDRUN,Bruneck/Brunico,2018-09-17,366,2021-08-27,745.0,230.0,216,0,26.0,966.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +10,Erklärung_Gemeinde_Pfitsch_2020.xlsx,HOFER EVA,Sozialgenossenschaft Tagesmütter - Gen.,Pfitsch,2017-07-10,HFRVEA17L50B160H,LETZNER PETRA,Pfitsch/Val di Vizze,2018-04-23,265,2020-09-21,875.0,348.0,304,0,-133.75,1089.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-21 +11,Erklärung_Gemeinde_Pfitsch_2020.xlsx,HOLZER LARISSA,Sozialgenossenschaft Tagesmütter - Gen.,Pfitsch,2016-08-11,HLZLSS16M51M067B,LETZNER PETRA,Pfitsch/Val di Vizze,2017-09-04,220,2020-08-07,244.75,168.0,152,0,41.75,454.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-07 +12,Erklärung_Gemeinde_Pfitsch_2020.xlsx,LASTA VALENTIN,Sozialgenossenschaft Tagesmütter - Gen.,Pfitsch,2017-05-18,LSTVNT17E18B160K,LETZNER PETRA,Pfitsch/Val di Vizze,2018-09-10,262,2020-09-18,588.25,306.0,250,0,-7.25,887.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +8,Erklärung_Gemeinde_Plaus_2020.xlsx,HOCHKOFLER NADINE,Sozialgenossenschaft Tagesmütter - Gen.,Plaus,2017-08-13,HCHNDN17M53I729Y,GURSCHLER ANDREA,Schluderns/Sluderno,2019-07-15,14,2020-01-14,14.5,0.0,0,0,0.0,14.5,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-01-14 +10,Erklärung_Gemeinde_Prad am Stilfser Joch_2020.xlsx,GRUBER IDA,Sozialgenossenschaft Tagesmütter - Gen.,Prad am Stilfser Joch,2017-01-18,GRBDIA17A58I729E,RADWANSKA KATARZYNA,Prad am Stilfser Joch/Prato allo Stelvio,2018-01-29,241,2020-08-28,235.5,163.0,116,0,-18.5,380.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +9,Erklärung_Gemeinde_Rasen-Antholz_2020.xlsx,KOFLER PAULI /,Sozialgenossenschaft Tagesmütter - Gen.,Rasen-Antholz,2019-06-24,KFLPLA19H24B220Y,PEINTNER CAROLIN,Rasen-Antholz/Rasun Anterselva,2020-09-22,101,2022-08-26,102.75,6.0,7,0,0.0,96.75,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,8,0,2020-09-22,2020-12-31 +12,Erklärung_Gemeinde_Rasen-Antholz_2020.xlsx,OBERFRANK LUIS,Sozialgenossenschaft Tagesmütter - Gen.,Rasen-Antholz,2017-01-09,BRFLSU17A09B220H,LERCHNER MARTA,Rasen-Antholz/Rasun Anterselva,2018-05-14,146,2020-05-25,143.5,170.0,277,0,234.0,547.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-05-25 +15,Erklärung_Gemeinde_Rasen-Antholz_2020.xlsx,STEINER EMMA /,Sozialgenossenschaft Tagesmütter - Gen.,Rasen-Antholz,2018-03-08,STNMME18C48B220A,PEINTNER CAROLIN,Rasen-Antholz/Rasun Anterselva,2020-08-03,151,2021-09-17,512.5,66.0,23,0,-96.5,452.0,,,,,,,,,,,,,,,,,,,,,,True,,,,0,8,0,2020-08-03,2020-12-31 +17,Erklärung_Gemeinde_Rasen-Antholz_2020.xlsx,STEINKASSERER ADRIAN,Sozialgenossenschaft Tagesmütter - Gen.,Rasen-Antholz,2017-01-18,STNDRN17A18B220I,LERCHNER MARTA,Rasen-Antholz/Rasun Anterselva,2017-09-11,241,2020-08-28,500.25,256.25,227,0,8.0,741.25,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +8,Erklärung_Gemeinde_Ratschings_2020.xlsx,GRAUS DAVID,Sozialgenossenschaft Tagesmütter - Gen.,Ratschings,2017-02-16,GRSDVD17B16B160N,LETZNER PETRA,Pfitsch/Val di Vizze,2019-09-15,241,2020-08-28,256.0,144.0,118,0,-15.0,385.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-08-28 +9,Erklärung_Gemeinde_Ratschings_2020.xlsx,HOFER LEO *,Sozialgenossenschaft Tagesmütter - Gen.,Ratschings,2018-03-02,HFRLEO18C02B160M,LETZNER PETRA,Pfitsch/Val di Vizze,2020-11-09,53,2021-08-27,79.25,29.75,14,0,0.0,96.25,,,,,,,,,,,,,,,,,,True,,,,True,,,,0,8,0,2020-11-09,2020-12-31 +9,Erklärung_Gemeinde_Ritten_2020.xlsx,BURCHIA PINO,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2017-10-15,BRCPNI17R15B160Y,BURGER SIMONE,Ritten/Renon,2020-03-02,99,2020-06-08,4.0,144.0,207,0,129.0,277.0,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-03-02,2020-06-08 +11,Erklärung_Gemeinde_Ritten_2020.xlsx,FILZ THIBAUD /neu,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2017-10-22,FLZTBD17R22A952S,LIENHART ELISABETH,Bozen/Bolzano,2020-05-19,116,2020-09-11,185.0,0.0,0,0,-152.0,33.0,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,0,0,2020-05-19,2020-09-11 +14,Erklärung_Gemeinde_Ritten_2020.xlsx,HOFER MILENA DOLORES,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2017-02-21,HFRMND17B61F132N,BURGER SIMONE,Ritten/Renon,2019-06-03,196,2020-07-14,195.25,252.0,237,0,180.5,627.75,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-14 +20,Erklärung_Gemeinde_Ritten_2020.xlsx,PLONER LEONIE,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2020-04-05,PLNLNE20D45A952Z,INNERHOFER MARTHA,Mölten/Meltina,2020-09-14,60,2020-11-12,96.75,6.75,0,0,0.0,96.75,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-09-14,2020-11-12 +21,Erklärung_Gemeinde_Ritten_2020.xlsx,PLONER MARIAN,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2018-07-26,PLNMRN18L26B160A,INNERHOFER MARTHA,Mölten/Meltina,2020-09-14,60,2020-11-12,96.75,6.75,0,0,0.0,96.75,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-09-14,2020-11-12 +22,Erklärung_Gemeinde_Ritten_2020.xlsx,RAGGI MATTIA,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2017-05-02,RGGMTT17E02B160Z,FINK PAULA,Ritten/Renon,2017-10-16,269,2020-09-25,414.75,210.0,185,0,49.0,673.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-25 +25,Erklärung_Gemeinde_Ritten_2020.xlsx,STEINWANDTER ARTHUR,Sozialgenossenschaft Tagesmütter - Gen.,Ritten,2017-12-17,STNRHR17T17F132Y,BURGER SIMONE,Ritten/Renon,2019-09-30,274,2020-09-30,509.0,336.0,254,0,96.0,941.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-30 +9,Erklärung_Gemeinde_Sarntal_2020.xlsx,LOCHER LENI,Sozialgenossenschaft Tagesmütter - Gen.,Sarntal,2017-11-23,LCHLNE17S63A952R,STUEFER DOROTHEA,Sarntal/Sarentino,2018-09-10,366,2021-08-27,442.0,148.0,126,0,-12.0,566.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,0,2020-01-01,2020-12-31 +11,Erklärung_Gemeinde_Sarntal_2020.xlsx,STAUDER JOHANNA *,Sozialgenossenschaft Tagesmütter - Gen.,Sarntal,2018-10-31,STDJNN18R71A952E,STUEFER DOROTHEA,Sarntal/Sarentino,2020-09-28,95,2021-09-03,142.5,35.0,13,0,0.0,162.5,,,,,,,,,,,,,,,,,,,,,,True,,,,0,8,0,2020-09-28,2020-12-31 +9,Erklärung_Gemeinde_Schlanders_2020.xlsx,DIETL JULIAN,Sozialgenossenschaft Tagesmütter - Gen.,Schlanders,2019-04-08,DTLJLN19D08I729J,UNTERTHURNER CARMEN,Schlanders/Silandro,2020-03-02,305,2022-09-02,204.0,587.75,217,0,17.5,809.25,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +10,Erklärung_Gemeinde_Schlanders_2020.xlsx,HAFELE ELINA AURELIA,Sozialgenossenschaft Tagesmütter - Gen.,Schlanders,2018-01-05,HFLLRL18A45I729A,UNTERTHURNER CARMEN,Schlanders/Silandro,2020-03-02,299,2020-12-25,126.0,677.75,195,0,-92.5,711.25,,,,,,,,,,,,,,,,,True,,,,,,,,,74,8,0,2020-03-02,2020-12-25 +13,Erklärung_Gemeinde_Schlanders_2020.xlsx,VILL LIAM,Sozialgenossenschaft Tagesmütter - Gen.,Schlanders,2018-05-15,VLLLMI18E15I729L,UNTERTHURNER CARMEN,Schlanders/Silandro,2020-10-12,23,2020-11-03,0.0,55.75,0,0,0.0,55.75,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-10-12,2020-11-03 +9,Erklärung_Gemeinde_Schenna_2020.xlsx,KAUFMANN JONAS /,Sozialgenossenschaft Tagesmütter - Gen.,Schenna,2018-11-22,KFMJNS18S22F132I,LEITNER ANNELIES,Lana/Lana,2019-09-02,182,2020-06-30,154.25,0.0,62,0,0.0,154.25,,,,,,,,,,,,,,,,,,,,,,True,,,,74,0,0,2020-01-01,2020-06-30 +9,Erklärung_Gemeinde_St.Lorenzen_2020.xlsx,PICHLER PAUL,Sozialgenossenschaft Tagesmütter - Gen.,St.Lorenzen,2019-09-05,PCHPLA19P05B220X,MAIRHOFER HEIDRUN,Bruneck/Brunico,2020-03-02,305,2022-09-02,516.0,247.0,201,0,19.75,749.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +8,Erklärung_Gemeinde_St.Pankraz_2020.xlsx,THALER YLENIA,Sozialgenossenschaft Tagesmütter - Gen.,St.Pankraz,2017-09-02,THLYLN17P42F132U,LAIMER HELGA,Lana/Lana,2017-10-09,182,2020-06-30,170.5,390.0,227,0,0.0,560.5,,,True,,,,,,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-30 +10,Erklärung_Gemeinde_Sterzing_2020.xlsx,TRATTER JOHANNES /,Sozialgenossenschaft Tagesmütter - Gen.,Sterzing,2018-08-26,TRTJNN18M26B160I,FÜRLER VERONIKA,Freienfeld/Campo di Trens,2020-08-13,141,2021-08-27,526.0,70.0,35,0,-99.0,497.0,,,,,,,,,,,,,,,,,,,True,True,True,True,,,,0,8,2,2020-08-13,2020-12-31 +10,Erklärung_Gemeinde_Terenten_2020.xlsx,INNERHOFER JULIAN,Sozialgenossenschaft Tagesmütter - Gen.,Terenten,2017-01-17,NNRJLN17A17B220Y,LECHNER MARTHA,Terenten/Terento,2018-01-08,178,2020-06-26,208.0,406.0,255,0,0.0,614.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-26 +8,Erklärung_Gemeinde_Tscherms_2020.xlsx,MAIRHOFER MARIE,Sozialgenossenschaft Tagesmütter - Gen.,Tscherms,2017-10-05,MRHMRA17R45F132N,LAGEDER JOHANNA,Lana/Lana,2019-10-07,366,2021-07-31,394.0,10.0,90,0,0.0,404.0,,,,,,,,,True,,,,,,,,,,,,True,,,,,74,8,0,2020-01-01,2020-12-31 +10,Erklärung_Gemeinde_Völs am Schlern_2020.xlsx,BAUMGARTNER PAUL //,Sozialgenossenschaft Tagesmütter - Gen.,Völs am Schlern,2019-09-29,BMGPLA19P29A952I,HASELRIEDER ANGELIKA,Völs am Schlern/Fie' allo Sciliar,2020-12-21,11,2022-08-26,13.5,0.0,0,0,0.0,13.5,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,0,0,2020-12-21,2020-12-31 +13,Erklärung_Gemeinde_Völs am Schlern_2020.xlsx,HOFER HANNAH,Sozialgenossenschaft Tagesmütter - Gen.,Völs am Schlern,2017-09-25,HFRHNH17P65B160X,HASELRIEDER ANGELIKA,Völs am Schlern/Fie' allo Sciliar,2018-04-23,262,2020-09-18,335.25,120.0,125,0,-11.5,443.75,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +18,Erklärung_Gemeinde_Welsberg_2020.xlsx,MOSER ELIAS,Sozialgenossenschaft Tagesmütter - Gen.,Welsberg,2018-08-18,MSRLSE18M18B220W,RAUTER INGE,Olang/Valdaora,2020-11-02,60,2021-08-27,84.0,16.0,13,0,0.0,100.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-02,2020-12-31 +11,Erklärung_Gemeinde_Algund_2020.xlsx,FLARER THEO,Sozialgenossenschaft Tagesmütter - Gen.,Algund,2018-07-11,FLRTHE18L11F132U,LADURNER JOHANNA,Meran/Merano,2020-03-02,305,2021-08-27,459.0,337.0,214,0,0.5,796.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,0,2020-03-02,2020-12-31 +16,Erklärung_Gemeinde_Algund_2020.xlsx,MIRANDOLA LENZ,Sozialgenossenschaft Tagesmütter - Gen.,Algund,2019-03-17,MRNLNZ19C17F132A,BRUNELLO CHRISTINE,Algund/Lagundo,2020-11-09,53,2022-08-12,74.5,23.75,14,0,0.0,98.25,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +8,Erklärung_Gemeinde_Branzoll_2020.xlsx,CABULA LEONARDO,Sozialgenossenschaft Tagesmütter - Gen.,Branzoll,2017-07-24,CBLLRD17L24A952H,PUFF CHRISTINA,Leifers/Laives,2020-01-27,340,2021-09-10,1199.5,348.0,371,0,4.0,1503.5,,,,,,,True,,True,,,,,,,,,,,,True,,,,,74,8,2,2020-01-27,2020-12-31 +11,Erklärung_Gemeinde_Bozen_2020.xlsx,ALBRECHT LEO,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2016-10-07,LBRLEO16R07A952F,STUEFER DOROTHEA,Sarntal/Sarentino,2017-10-08,248,2020-09-04,0.0,240.0,86,0,49.0,289.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-04 +12,Erklärung_Gemeinde_Bozen_2020.xlsx,ALBRECHT LEO /,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2016-10-07,LBRLEO16R07A952F,SPERANZA ROMINA,Bozen/Bolzano,2017-10-08,248,2020-09-04,464.5,0.0,138,0,0.0,464.5,,,,,,,,True,,,,,,,,,,,,,,True,,,,74,0,0,2020-01-01,2020-09-04 +13,Erklärung_Gemeinde_Bozen_2020.xlsx,ALESSI CLOE,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2020-03-11,LSSCLO20C51F132E,KLOSTERMAIER EVELYN,Bozen/Bolzano,2020-11-02,29,2020-11-30,20.0,32.5,15,0,0.0,46.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,2,2020-11-02,2020-11-30 +14,Erklärung_Gemeinde_Bozen_2020.xlsx,ANDRIGO THOMAS,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-02-06,NDRTMS17B06A952J,MENAPACE ELENA,Bozen/Bolzano,2018-09-10,192,2020-07-10,414.5,308.0,306,0,71.5,794.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-07-10 +16,Erklärung_Gemeinde_Bozen_2020.xlsx,BAUMGARTNER PAUL /,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2019-09-29,BMGPLA19P29A952I,HASELRIEDER ANGELIKA,Völs am Schlern/Fie' allo Sciliar,2020-08-17,126,2020-12-20,360.75,0.0,22,0,-8.5,352.25,,,,,,,,,,,,,,,,,,,,,True,True,,,,0,8,0,2020-08-17,2020-12-20 +19,Erklärung_Gemeinde_Bozen_2020.xlsx,BERTACCHE SAMUEL,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-09-23,BRTSML17P23A952Y,BONADIO CONCETTA,Bozen/Bolzano,2018-09-10,40,2020-02-09,54.0,0.0,0,0,0.0,54.0,,,,,,,,,,,,,,,,,,,,,True,,,,,0,0,0,2020-01-01,2020-02-09 +20,Erklärung_Gemeinde_Bozen_2020.xlsx,BERTI RAPHAEL,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-01-07,BRTRHL17A07A952C,STEGER SONYA,Bozen/Bolzano,2018-09-03,178,2020-06-26,163.0,200.0,249,0,236.0,599.0,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-26 +24,Erklärung_Gemeinde_Bozen_2020.xlsx,BOVA SOPHIE,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2019-04-15,BVOSPH19D55A952V,BONADIO CONCETTA,Bozen/Bolzano,2020-11-02,60,2022-09-02,94.0,91.5,21,0,0.0,128.5,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,2,2020-11-02,2020-12-31 +32,Erklärung_Gemeinde_Bozen_2020.xlsx,DAPUNT ZEILINGER MIRA,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-04-10,DPNMRI17D50Z102Q,STEGER SONYA,Bozen/Bolzano,2019-08-26,366,2021-01-24,73.0,0.0,16,0,0.0,73.0,,,,,,,,,True,,,,,,,,,,,,,,,,,74,8,2,2020-01-01,2020-12-31 +40,Erklärung_Gemeinde_Bozen_2020.xlsx,FILIPPIN ETTORE,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2016-10-13,FLPTTR16R13A952A,WERTH AGATHA,Bozen/Bolzano,2017-09-18,248,2020-09-04,735.25,376.0,333,0,7.25,1118.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-04 +41,Erklärung_Gemeinde_Bozen_2020.xlsx,FILZ THIBAUD,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-10-22,FLZTBD17R22A952S,LIENHART ELISABETH,Bozen/Bolzano,2018-05-07,255,2020-09-11,271.0,391.0,284,0,319.0,981.0,,,,,,,,,,,,,,,,,,,,,True,,,,,74,0,0,2020-01-01,2020-09-11 +67,Erklärung_Gemeinde_Bozen_2020.xlsx,OCHSENREITER JAKOB,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2020-08-06,CHSJKB20M06A952B,GASSER MARIANNA,Bozen/Bolzano,2020-11-09,53,2023-08-25,92.0,32.0,17,0,0.0,116.0,,,,,,,,,,,,,,,,,,True,,,,,,,,0,8,0,2020-11-09,2020-12-31 +76,Erklärung_Gemeinde_Bozen_2020.xlsx,PREMSTALLER FELIX,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-01-13,PRMFLX17A13A952N,DIETRICH MARGRIT,Bozen/Bolzano,2018-09-10,179,2020-06-27,128.5,250.0,267,0,269.0,647.5,,,,,,,,True,,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-06-27 +77,Erklärung_Gemeinde_Bozen_2020.xlsx,RATSCHILLER ANTON LEO,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-06-25,RTSNNL17H25F132F,WIPFLER MARIETTA KATHARINA,Bozen/Bolzano,2018-01-15,262,2020-09-18,529.5,460.0,305,0,91.0,1080.5,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-18 +78,Erklärung_Gemeinde_Bozen_2020.xlsx,RIVELLI CASTILLO LOLA,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-06-02,RVLLLO17H42Z404I,MENAPACE ELENA,Bozen/Bolzano,2020-02-24,174,2020-08-15,182.5,286.0,225,0,62.0,530.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,0,0,2020-02-24,2020-08-15 +83,Erklärung_Gemeinde_Bozen_2020.xlsx,SAILER SENI,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2017-06-23,SLRSNE17H23A952H,POLITI MARINA,Bozen/Bolzano,2019-08-19,269,2020-09-25,761.0,330.0,317,0,63.25,1154.25,,,,,,,,,True,,,,,,,,,,,,,,,,,74,0,0,2020-01-01,2020-09-25 +87,Erklärung_Gemeinde_Bozen_2020.xlsx,SIMONETTO GHELLER MATTEO,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2019-05-15,SMNMTT19E15A952W,SPERANZA ROMINA,Bozen/Bolzano,2020-03-02,305,2021-06-25,797.0,261.5,297,0,31.5,1078.5,,,,,,,,,,,,,,,,True,True,,,,,,,,,74,8,2,2020-03-02,2020-12-31 +106,Erklärung_Gemeinde_Bozen_2020.xlsx,ZINGERLE MATHILDA,Sozialgenossenschaft Tagesmütter - Gen.,Bozen,2019-06-24,ZNGMHL19H64A952H,CANDOTTI MARTINA,Bozen/Bolzano,2020-03-02,305,2022-08-26,321.5,138.0,125,0,-3.5,456.0,,,,,,,,,,,,,,,,,True,,,,,,,,,74,8,2,2020-03-02,2020-12-31 diff --git a/pages/testPDF.pdf b/pages/testPDF.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d549deda8f6851c90b2c6052fb2cbeb3e13cfb08 Binary files /dev/null and b/pages/testPDF.pdf differ diff --git a/requirements.txt b/requirements.txt index 28d994e22f8dd432b51df193562052e315ad95f7..296642bee9a813227b5611f2fa50d4f137a41239 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,9 @@ -altair pandas -streamlit \ No newline at end of file +openpyxl +numpy +streamlit-ext +streamlit-aggrid +xlsxwriter +streamlit +reportlab +setuptools \ No newline at end of file diff --git a/utilities/helpertools_TM.py b/utilities/helpertools_TM.py new file mode 100644 index 0000000000000000000000000000000000000000..fc88a01640f102a99238e9cc140716629bd66ef2 --- /dev/null +++ b/utilities/helpertools_TM.py @@ -0,0 +1,147 @@ +import pandas as pd +from typing import Optional, List, Dict, Any +import streamlit as st + +class helpers: + """ + A utility class that provides helper methods for data processing and error handling. + + This class contains methods for converting dates, filtering error records, and + managing DataFrame columns in the context of data validation and reporting. + + Attributes: + interface: Interface object containing configuration settings + ERRDICT: Dictionary containing error definitions and descriptions + """ + + def __init__(self, interface = None, errdict = None): + """ + Initialize the helpers class with interface and error dictionary. + + Args: + interface: Interface object containing configuration settings + errdict: Dictionary containing error definitions and descriptions + """ + self.interface = interface + self.ERRDICT = errdict + + def get_version(self) -> str: + return "Helpertools 1.0.0" + + def convert_dates_if_needed(self, df: pd.DataFrame, date_cols: List[str] = None) -> pd.DataFrame: + """ + Converts date columns in the DataFrame to string format based on configuration. + + This method handles date conversions according to the interface configuration. + It can either convert specific date columns or use default date column names. + + Args: + df (pd.DataFrame): The DataFrame containing date columns to convert + date_cols (List[str], optional): List of column names containing dates. + Defaults to None, which uses predefined columns. + + Returns: + pd.DataFrame: DataFrame with converted date columns + + Raises: + Exception: If date conversion fails and TOLLERANZAZERO is True + """ + if self.interface.CONVERTIDATESTRINGHE: + try: + # Convert 'Data di nascita' column + df["Data di nascita"] = df["Data di nascita"].dt.strftime('%d/%m/%Y') + + # Convert 'Data fine contratto (o data fine assistenza se diversa)' column + df["Data fine contratto (o data fine assistenza se diversa)"] = df["Data fine contratto (o data fine assistenza se diversa)"].dt.strftime('%d/%m/%Y') + + # Convert 'Data inizio contratto (o data inizio assistenza se diversa)' column + df["Data inizio contratto (o data inizio assistenza se diversa)"] = df["Data inizio contratto (o data inizio assistenza se diversa)"].dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date in stringhe; errore: {e}") + if self.interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + else: + if not date_cols: + date_cols = ["Data di nascita", "Data inizio contratto (o data inizio assistenza se diversa)", "Data fine contratto (o data fine assistenza se diversa)"] + try: + for col in date_cols: + if col in df.columns: + # Convert to datetime (coerce errors) and then to string + df[col] = pd.to_datetime(df[col], errors='coerce').dt.strftime('%d/%m/%Y') + except Exception as e: + st.error(f"Errore durante conversione date, errore: {e}") + if self.interface.TOLLERANZAZERO: + st.error("Elaborazione terminata") + st.stop() + return df + + + def make_df_solo_errori(self, df) -> pd.DataFrame: + """ + Creates a DataFrame containing only records with errors. + + This method filters the input DataFrame to include only rows that have + at least one error flag set to True, excluding specific error types like + 'errMassimo543'. + + Args: + df (pd.DataFrame): The input DataFrame containing error flag columns + + Returns: + pd.DataFrame: A filtered DataFrame containing only records with errors + """ + dffinal: pd.DataFrame = df + # Create logical condition + # at least one error per error type + for e in self.ERRDICT: + + # do not want this column in the "error" df as there are too many of them + if e == "errMassimo543": + continue + # first instance of "condition" # this way, it is created with the correct type + # local() contiene variabili e functions nel namespace locale + if "condizione" not in locals(): + condizione: pd.Series = dffinal[e] == True + else: + # simple solution: concatenate conditions for checks made + condizione: pd.Series = condizione | dffinal[e] == True + + # create df with only records with error + dffinal = dffinal[condizione] + + return dffinal + + def drop_columns(self, df: pd.DataFrame, errordict) -> pd.DataFrame: + """ + Drops specified columns from the DataFrame based on error dictionary keys. + + This method attempts to remove columns specified in the error dictionary. + It handles cases where columns may not exist in the DataFrame and provides + appropriate warnings. + + Args: + df (pd.DataFrame): The DataFrame to modify + errordict (Dict): Dictionary containing column names to drop + + Returns: + pd.DataFrame: The modified DataFrame with specified columns removed + + Raises: + Exception: If column removal fails and TOLLERANZAZERO is True + """ + #st.write(errordict) + # Drop columns based on keys in ERRORDICT + for k in errordict.keys(): + #st.write(k) + try: + df = df.drop([k], axis=1) + except Exception as e: + # if self.DEBUGGENERAL: + st.warning( + f"Non è stato possibile trovare la colonna {k}; errore: {e}" + ) + if self.DEBUGWARNINGS or self.TOLLERANZAZERO: + st.error("Esecuzione terminata") + st.stop() + return df \ No newline at end of file diff --git a/utilities/interface.py b/utilities/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..423672ca3bf32b86cbfe80f940d8170be732d4eb --- /dev/null +++ b/utilities/interface.py @@ -0,0 +1,623 @@ +import pandas as pd +import numpy as np +import streamlit as st +import streamlit as ste +from typing import Optional, List, Dict, Any + +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from io import BytesIO +import xlsxwriter +from datetime import date, datetime + +from utilities.helpertools_TM import helpers + +helper = helpers() + + +class makeInterface: + """ + A class to create and manage the user interface for data validation and processing. + + This class handles file uploads, creates the interface layout, manages validation checks, + and provides functionality for displaying and downloading results. + + Attributes: + valori: Configuration values and constants for the interface + ANNO_RIFERIMENTO (str): The reference year for data validation + DEBUGWARNINGS (bool): Flag for showing debug warnings + TOLLERANZAZERO (bool): Flag for zero tolerance mode + ERRORDICT (dict): Dictionary of error types and descriptions + ERROR_ICONS (dict): Dictionary mapping error types to their icons + """ + + def __init__(self, valori): + """ + Initialize the interface with configuration values. + + Args: + valori: Object containing configuration values and constants + """ + self.valori = valori + # self.ERRDICT = ERRDICT + # st.write(ERRDICT) + # Add spacer at the top of sidebar to push elements down + st.sidebar.markdown('
', unsafe_allow_html=True) + # st.write(self.ERRDICT) + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023","2024", "2025", "2026"]), index=1 + ) + self.make_sidebar() + self.DEBUGWARNINGS = False + self.TOLLERANZAZERO = False + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + + # Use the unified file upload method instead of the separate ones + self.upload_all_files() + self.choose_checks() + self.apply_custom_theme() + + def apply_custom_theme(self): + """Apply custom styling to improve the overall appearance of the interface.""" + st.markdown(""" + + """, unsafe_allow_html=True) + + def get_version(self) -> str: + return "Interface 1.0.0" + + def make_sidebar(self): + """ + Create the sidebar interface with configuration options. + + Creates checkboxes and radio buttons for various settings including: + - Integrity message display + - Date string conversion + - Processing interruption settings + - Constants display + - General debug mode + """ + + # st.sidebar.info("Einstellungen") + # expander = st.sidebar.expander("Impostazioni generali") + with st.sidebar.expander("Configurazione"): + self.COMUNETEDESCO = st.checkbox( + "Mostra comuni in tedesco", False + ) + self.MOSTRAERRORIINTEGRITA = st.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.checkbox( + "Convertire le date in stringhe", True + ) + self.INTERRUZIONE = st.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + + self.MOSTRACOSTANTI = st.checkbox("Mostra costanti per anno riferimento") + if self.MOSTRACOSTANTI: + try: + st.info(self.valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.error("Impossibile mostrare costanti") + + self.DEBUGGENERAL = st.checkbox("Debug generale") + + + + + def get_file_list(self): + """ + Create a file uploader for selecting multiple Excel files. + """ + self.uploaded_files = st.file_uploader( + "Excel Dateien auswaehlen", accept_multiple_files=True + ) + # st.write(self.filelist) + + def make_expander(self, title1, title2, count, dftemp): + """ + Create an expandable section to display data results. + + Args: + title1 (str): Primary title for the expander + title2 (str): Secondary title/description + count (int): Number of occurrences found + dftemp (pd.DataFrame): DataFrame containing the results to display + """ + with st.expander(f"Trovate **{count}** occorrenze per {title1}"): + st.info(title2) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + title1, + ) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + f"{title1}.xlsx", + ) + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + +# def choose_files(self, c1) -> None: +# """Allow users to upload multiple Excel files for checking.""" +# self.uploaded_files: List[FileUploadBase] = c1.file_uploader( +# "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True +# ) + +# def choose_allegato666(self, c2) -> None: +# """ +# Allow users to upload the Allegato 666 file for checking.# + +# Args: +# None + + # Returns: + # None + # """ + # self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + # "CARICARE ALLEGATO 666", accept_multiple_files=False + # ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks", + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate( + self.ERRORDICT.items() + ): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox", + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, "TOLLERANZAZERO", False) or getattr( + self, "DEBUGWARNINGS", False + ): + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self) -> None: + """ + Create the main navigation tabs for the application. + + Creates three tabs: + - Data Integrity + - Errors and Inconsistencies + - Final Tables + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Build a grid configuration for displaying tabular data. + + Args: + data (pd.DataFrame): The DataFrame to be displayed in the grid + + Returns: + dict: Grid options configuration for AG-Grid + """ + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Create and display an interactive data grid. + + Args: + dff (pd.DataFrame): DataFrame to be displayed in the grid + k (str): Unique key identifier for the grid component + """ + # st.write(dff) + # Drop unnecessary columns from the DataFrame + helper = helpers() + dff = helper.drop_columns(dff, self.ERRORDICT) + # st.write(dff) + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def download_excel_file(self, dftosave: pd.DataFrame, nome_file: str, flag: Optional[str] = None) -> None: + """ + Create and provide a download button for an Excel file with improved styling. + + Args: + dftosave (pd.DataFrame): DataFrame to be saved as Excel + nome_file (str): Name of the output file + flag (Optional[str]): Flag to control column handling ('mantieniColonneErrore' to keep error columns) + + Raises: + KeyError: If required columns are missing from the DataFrame + ValueError: If there are invalid or incompatible values + Exception: For other unexpected errors + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop( + columns=["Colonna_L_da_cancellare_dopo"], errors="ignore" + ) + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f"{timestamp}_{nome_file}" + + # Step 3: Drop columns based on the flag + if flag == "mantieniColonneErrore": + pass + else: + dftosave = helper.drop_columns(dftosave, self.ERRORDICT) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Add a header format + header_format = workbook.add_format({ + 'bold': True, + 'bg_color': '#4E8CFF', + 'color': 'white', + 'border': 1, + 'align': 'center' + }) + + # Add data format + data_format = workbook.add_format({ + 'border': 1 + }) + + # Apply the header format to the first row + for col_num, value in enumerate(dftosave.columns.values): + worksheet.write(0, col_num, value, header_format) + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length, data_format) + + # Add autofilter + worksheet.autofilter(0, 0, len(dftosave), len(dftosave.columns) - 1) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Better styled download section + col1, col2 = st.columns([1, 2]) + + with col1: + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Scarica Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + use_container_width=True, + ) + + with col2: + st.markdown(f""" +
+ File: {nome_file}
+ Righe: {len(dftosave)} | Colonne: {len(dftosave.columns)} +
+ """, unsafe_allow_html=True) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def upload_all_files(self) -> None: + """ + Allow users to upload all Excel files at once, automatically identifying the Allegato 666 file. + Enhanced with better visual styling and a single clear upload area. + """ + st.markdown("### 📁 Upload file Excel") + + # Apply custom CSS to style the file uploader and hide the uploaded files display + st.markdown(""" + + """, unsafe_allow_html=True) + + # File uploader with empty label (our CSS will provide the instructions) + all_uploaded_files = st.file_uploader( + "", + accept_multiple_files=True, + label_visibility="collapsed" + ) + + # Initialize as empty lists + self.uploaded_files = [] + self.uploaded_allegato666 = None + + # Check if any files were uploaded + if all_uploaded_files: + # Define valid Excel file extensions + valid_extensions = ['.xlsx', '.xls'] + + # Separate valid Excel files from invalid ones + valid_files = [] + invalid_files = [] + + for file in all_uploaded_files: + # Check if file has a valid Excel extension + file_extension = '.' + file.name.split('.')[-1].lower() + if file_extension in valid_extensions: + valid_files.append(file) + else: + invalid_files.append(file) + + # Display warning for invalid files + if invalid_files: + invalid_file_names = [file.name for file in invalid_files] + st.markdown(f""" +
+

❌ Errore: I seguenti file non sono in formato Excel e non verranno elaborati:

+
    + {''.join([f'
  • {name}
  • ' for name in invalid_file_names])} +
+
+ """, unsafe_allow_html=True) + + # Process only valid Excel files + allegato_666_files = [] + other_files = [] + + for file in valid_files: + if "666" in file.name: + allegato_666_files.append(file) + else: + other_files.append(file) + + # Assign the regular files to self.uploaded_files + self.uploaded_files = other_files + + # Handle Allegato 666 file(s) and display messages using styled cards + if len(allegato_666_files) > 0 or len(other_files) > 0: + col1, col2 = st.columns(2) + + # Handle Allegato 666 file(s) with better styling + with col1: + if len(allegato_666_files) == 1: + self.uploaded_allegato666 = allegato_666_files[0] + st.markdown(f""" +
+

✅ Allegato 666: {self.uploaded_allegato666.name}

+
+ """, unsafe_allow_html=True) + elif len(allegato_666_files) > 1: + st.markdown(f""" +
+

❌ Errore: Più file contengono '666' nel nome ({len(allegato_666_files)})

+
+ """, unsafe_allow_html=True) + self.uploaded_allegato666 = None + else: + st.markdown(f""" +
+

⚠️ Attenzione: Allegato 666 mancante

+
+ """, unsafe_allow_html=True) + + # Display count of regular files with better styling + with col2: + if len(other_files) > 0: + st.markdown(f""" +
+

ℹ️ Elenchi caricati: {len(other_files)}

+
+ """, unsafe_allow_html=True) + + # Add an expander to show file list + with st.expander("Mostra file caricati"): + for file in other_files: + st.markdown(f"📄 {file.name}") + else: + st.markdown(f""" +
+

⚠️ Attenzione: Nessun file Excel aggiuntivo

+
+ """, unsafe_allow_html=True) + + # Add vertical spacing after the status boxes + st.markdown("
", unsafe_allow_html=True) diff --git a/utilities/interface.py.broken b/utilities/interface.py.broken new file mode 100644 index 0000000000000000000000000000000000000000..674ec9c49e7dabf1e8e01c0265784706888a432d --- /dev/null +++ b/utilities/interface.py.broken @@ -0,0 +1,893 @@ +import pandas as pd +import numpy as np +import streamlit as st +import streamlit as ste +from typing import Optional, List, Dict, Any + +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from io import BytesIO +import xlsxwriter +from datetime import date, datetime + +from utilities.helpertools_TM import helpers + +helper = helpers() + + +class makeInterface: + """ + A class to create and manage the user interface for data validation and processing. + + This class handles file uploads, creates the interface layout, manages validation checks, + and provides functionality for displaying and downloading results. + + Attributes: + valori: Configuration values and constants for the interface + ANNO_RIFERIMENTO (str): The reference year for data validation + DEBUGWARNINGS (bool): Flag for showing debug warnings + TOLLERANZAZERO (bool): Flag for zero tolerance mode + ERRORDICT (dict): Dictionary of error types and descriptions + ERROR_ICONS (dict): Dictionary mapping error types to their icons + """ + + def __init__(self, valori): + """ + Initialize the interface with configuration values. + + Args: + valori: Object containing configuration values and constants + """ + self.valori = valori + + # Create the modern header + self.make_header() + + # Add spacer at the top of sidebar to push elements down + st.sidebar.markdown('
', unsafe_allow_html=True) + # st.write(self.ERRDICT) + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023","2024", "2025", "2026"]), index=1 + ) + self.make_sidebar() + self.DEBUGWARNINGS = False + self.TOLLERANZAZERO = False + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + + # Use the unified file upload method instead of the separate ones + self.upload_all_files() + self.choose_checks() + self.apply_custom_theme() + + def make_header(self): + """Create an attractive header section for the application.""" + st.markdown(""" +
+

Excel Validator

+

Analizza e valida facilmente i file Excel

+
+ """, unsafe_allow_html=True) + + def apply_custom_theme(self): + """Apply custom styling to improve the overall appearance of the interface.""" + st.markdown(""" + + """, unsafe_allow_html=True) + + def get_version(self) -> str: + return "Interface 1.0.0" + + def make_sidebar(self): + """ + Create the sidebar interface with configuration options. + + Creates checkboxes and radio buttons for various settings including: + - Integrity message display + - Date string conversion + - Processing interruption settings + - Constants display + - General debug mode + """ + # Apply custom styling to the sidebar + self.style_sidebar() + + with st.sidebar.expander("Configurazione", expanded=True): + self.MOSTRAERRORIINTEGRITA = st.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.checkbox( + "Convertire le date in stringhe", True + ) + self.INTERRUZIONE = st.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + + self.MOSTRACOSTANTI = st.checkbox("Mostra costanti per anno riferimento") + if self.MOSTRACOSTANTI: + try: + st.info(self.valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.error("Impossibile mostrare costanti") + + self.DEBUGGENERAL = st.checkbox("Debug generale") + + # Add theme toggle option + self.add_theme_toggle() + + def style_sidebar(self): + """Apply custom styling to the sidebar.""" + # Define version for formatting + version = self.get_version() + + # Use single quotes for the style string to avoid issues with formatting + st.sidebar.markdown(''' + + ''', unsafe_allow_html=True) + + # Add version info in a separate markdown to avoid string interpolation issues + st.sidebar.markdown(f''' +
+

Excel Validator

+

v{version}

+
+ ''', unsafe_allow_html=True) + + def get_file_list(self): + """ + Create a file uploader for selecting multiple Excel files. + """ + self.uploaded_files = st.file_uploader( + "Excel Dateien auswaehlen", accept_multiple_files=True + ) + # st.write(self.filelist) + + def make_expander(self, title1, title2, count, dftemp): + """ + Create an expandable section to display data results. + + Args: + title1 (str): Primary title for the expander + title2 (str): Secondary title/description + count (int): Number of occurrences found + dftemp (pd.DataFrame): DataFrame containing the results to display + """ + with st.expander(f"Trovate **{count}** occorrenze per {title1}"): + st.info(title2) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + title1, + ) + + self.download_excel_file( + dftosave=dftemp.sort_values(by=["Cognome", "Nome"]), + nome_file=f"{title1}.xlsx", + ) + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + +# def choose_files(self, c1) -> None: +# """Allow users to upload multiple Excel files for checking.""" +# self.uploaded_files: List[FileUploadBase] = c1.file_uploader( +# "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True +# ) + +# def choose_allegato666(self, c2) -> None: +# """ +# Allow users to upload the Allegato 666 file for checking.# + +# Args: +# None + + # Returns: + # None + # """ + # self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + # "CARICARE ALLEGATO 666", accept_multiple_files=False + # ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks", + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate( + self.ERRORDICT.items() + ): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox", + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, "TOLLERANZAZERO", False) or getattr( + self, "DEBUGWARNINGS", False + ): + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self) -> None: + """ + Create the main navigation tabs for the application with icons for better visual appeal. + + Creates three tabs: + - Data Integrity + - Errors and Inconsistencies + - Final Tables + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs([ + "🧩 INTEGRITÀ DATI", + "🔍 ERRORI e INCONGRUENZE", + "📊 TABELLE FINALI" + ]) + + # Add additional styling for tabs + st.markdown(""" + + """, unsafe_allow_html=True) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Build a grid configuration for displaying tabular data. + + Args: + data (pd.DataFrame): The DataFrame to be displayed in the grid + + Returns: + dict: Grid options configuration for AG-Grid + """ + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Create and display an interactive data grid. + + Args: + dff (pd.DataFrame): DataFrame to be displayed in the grid + k (str): Unique key identifier for the grid component + """ + # st.write(dff) + # Drop unnecessary columns from the DataFrame + helper = helpers() + dff = helper.drop_columns(dff, self.ERRORDICT) + # st.write(dff) + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def download_excel_file(self, dftosave: pd.DataFrame, nome_file: str, flag: Optional[str] = None) -> None: + """ + Create and provide a download button for an Excel file with improved styling. + + Args: + dftosave (pd.DataFrame): DataFrame to be saved as Excel + nome_file (str): Name of the output file + flag (Optional[str]): Flag to control column handling ('mantieniColonneErrore' to keep error columns) + + Raises: + KeyError: If required columns are missing from the DataFrame + ValueError: If there are invalid or incompatible values + Exception: For other unexpected errors + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop( + columns=["Colonna_L_da_cancellare_dopo"], errors="ignore" + ) + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f"{timestamp}_{nome_file}" + + # Step 3: Drop columns based on the flag + if flag == "mantieniColonneErrore": + pass + else: + dftosave = helper.drop_columns(dftosave, self.ERRORDICT) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Add a header format + header_format = workbook.add_format({ + 'bold': True, + 'bg_color': '#4E8CFF', + 'color': 'white', + 'border': 1, + 'align': 'center' + }) + + # Add data format + data_format = workbook.add_format({ + 'border': 1 + }) + + # Apply the header format to the first row + for col_num, value in enumerate(dftosave.columns.values): + worksheet.write(0, col_num, value, header_format) + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length, data_format) + + # Add autofilter + worksheet.autofilter(0, 0, len(dftosave), len(dftosave.columns) - 1) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Better styled download section + col1, col2 = st.columns([1, 2]) + + with col1: + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Scarica Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + use_container_width=True, + ) + + with col2: + st.markdown(f""" +
+ File: {nome_file}
+ Righe: {len(dftosave)} | Colonne: {len(dftosave.columns)} +
+ """, unsafe_allow_html=True) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def upload_all_files(self) -> None: + """ + Allow users to upload all Excel files at once, automatically identifying the Allegato 666 file. + Enhanced with better visual styling and a single clear upload area. + """ + st.markdown("### 📁 Upload file Excel") + + # Apply custom CSS to style the file uploader and hide the uploaded files display + st.markdown(""" + + """, unsafe_allow_html=True) + + # File uploader with empty label (our CSS will provide the instructions) + all_uploaded_files = st.file_uploader( + "", + accept_multiple_files=True, + label_visibility="collapsed" + ) + + # Initialize as empty lists + self.uploaded_files = [] + self.uploaded_allegato666 = None + + # Check if any files were uploaded + if all_uploaded_files: + # Define valid Excel file extensions + valid_extensions = ['.xlsx', '.xls'] + + # Separate valid Excel files from invalid ones + valid_files = [] + invalid_files = [] + + for file in all_uploaded_files: + # Check if file has a valid Excel extension + file_extension = '.' + file.name.split('.')[-1].lower() + if file_extension in valid_extensions: + valid_files.append(file) + else: + invalid_files.append(file) + + # Display warning for invalid files + if invalid_files: + invalid_file_names = [file.name for file in invalid_files] + st.markdown(f""" +
+

❌ Errore: I seguenti file non sono in formato Excel e non verranno elaborati:

+
    + {''.join([f'
  • {name}
  • ' for name in invalid_file_names])} +
+
+ """, unsafe_allow_html=True) + + # Process only valid Excel files + allegato_666_files = [] + other_files = [] + + for file in valid_files: + if "666" in file.name: + allegato_666_files.append(file) + else: + other_files.append(file) + + # Assign the regular files to self.uploaded_files + self.uploaded_files = other_files + + # Handle Allegato 666 file(s) and display messages using styled cards + if len(allegato_666_files) > 0 or len(other_files) > 0: + col1, col2 = st.columns(2) + + # Handle Allegato 666 file(s) with better styling + with col1: + if len(allegato_666_files) == 1: + self.uploaded_allegato666 = allegato_666_files[0] + st.markdown(f""" +
+

✅ Allegato 666: {self.uploaded_allegato666.name}

+
+ """, unsafe_allow_html=True) + elif len(allegato_666_files) > 1: + st.markdown(f""" +
+

❌ Errore: Più file contengono '666' nel nome ({len(allegato_666_files)})

+
+ """, unsafe_allow_html=True) + self.uploaded_allegato666 = None + else: + st.markdown(f""" +
+

⚠️ Attenzione: Allegato 666 mancante

+
+ """, unsafe_allow_html=True) + + # Display count of regular files with better styling + with col2: + if len(other_files) > 0: + st.markdown(f""" +
+

ℹ️ Elenchi caricati: {len(other_files)}

+
+ """, unsafe_allow_html=True) + + # Add an expander to show file list + with st.expander("Mostra file caricati"): + for file in other_files: + st.markdown(f"📄 {file.name}") + else: + st.markdown(f""" +
+

⚠️ Attenzione: Nessun file Excel aggiuntivo

+
+ """, unsafe_allow_html=True) + + # Add vertical spacing after the status boxes + st.markdown("
", unsafe_allow_html=True) + + def add_theme_toggle(self): + """Add a theme toggle button in the sidebar.""" + theme = st.sidebar.radio( + "Tema", + ["Chiaro", "Scuro"], + horizontal=True + ) + + if theme == "Scuro": + st.markdown(""" + + """, unsafe_allow_html=True) + + def display_status_message(self, message_type, message): + """ + Display a styled status message with appropriate icon. + + Args: + message_type (str): Type of message ('success', 'info', 'warning', 'error') + message (str): The message content to display + """ + icons = { + "success": "✅", + "info": "ℹ️", + "warning": "⚠️", + "error": "❌" + } + colors = { + "success": "#d1f0d9", + "info": "#d1e7f0", + "warning": "#fff8e1", + "error": "#ffdcdc" + } + border_colors = { + "success": "#2e7d32", + "info": "#1976d2", + "warning": "#ff9800", + "error": "#d32f2f" + } + + st.markdown(f""" +
+
{icons[message_type]}
+
{message}
+
+ """, unsafe_allow_html=True) + + def process_with_progress(self, files): + """ + Process files with a visual progress indicator to improve user experience. + + Args: + files (list): List of files to process + """ + if not files: + return + + # Create a stylish progress container + progress_container = st.container() + + with progress_container: + # Create progress elements + st.markdown(""" + + """, unsafe_allow_html=True) + + progress_text = st.empty() + progress_bar = st.progress(0) + file_status = st.empty() + + for i, file in enumerate(files): + # Update progress display + progress = int((i + 1) / len(files) * 100) + progress_bar.progress(progress) + progress_text.markdown(f""" +
+ Elaborazione in corso... + {i+1} di {len(files)} +
+ """, unsafe_allow_html=True) + + file_status.markdown(f""" +
+
+
📄
+
+ Processando: {file.name} +
+
+
+ """, unsafe_allow_html=True) + + # Process your file here + # Your file processing code goes here + + # Add a small delay to make the progress visible + import time + time.sleep(0.2) + + # Complete the progress + progress_bar.progress(100) + progress_text.markdown(""" +
+ ✅ Elaborazione completata! +
+ """, unsafe_allow_html=True) + file_status.empty() + + # Keep the completed bar for a moment then clear it + time.sleep(1.5) + progress_container.empty() + + def create_feature_cards(self): + """Create card-based layout for main features.""" + col1, col2 = st.columns(2) + + with col1: + st.markdown(""" +
+

📁 Carica File

+

Carica i tuoi file Excel per la validazione e analisi.

+
+ """, unsafe_allow_html=True) + # Add the file uploader here + + with col2: + st.markdown(""" +
+

⚙️ Configurazione

+

Seleziona i controlli da eseguire sui dati.

+
+ """, unsafe_allow_html=True) + # Add configuration options here diff --git a/utilities/interface.py.org b/utilities/interface.py.org new file mode 100644 index 0000000000000000000000000000000000000000..c2d0ffdc037c6149fd86248e93f84ab36467db63 --- /dev/null +++ b/utilities/interface.py.org @@ -0,0 +1,437 @@ +import pandas as pd +import numpy as np +import streamlit as st +import streamlit as ste +from typing import Optional, List, Dict, Any + +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from io import BytesIO +import xlsxwriter +from datetime import date, datetime + +from utilities.helpertools_TM import helpers + +helper = helpers() + + +class makeInterface: + """ + A class to create and manage the user interface for data validation and processing. + + This class handles file uploads, creates the interface layout, manages validation checks, + and provides functionality for displaying and downloading results. + + Attributes: + valori: Configuration values and constants for the interface + ANNO_RIFERIMENTO (str): The reference year for data validation + DEBUGWARNINGS (bool): Flag for showing debug warnings + TOLLERANZAZERO (bool): Flag for zero tolerance mode + ERRORDICT (dict): Dictionary of error types and descriptions + ERROR_ICONS (dict): Dictionary mapping error types to their icons + """ + + def __init__(self, valori): + """ + Initialize the interface with configuration values. + + Args: + valori: Object containing configuration values and constants + """ + self.valori = valori + # self.ERRDICT = ERRDICT + # st.write(ERRDICT) + + # st.write(self.ERRDICT) + self.ANNO_RIFERIMENTO = st.sidebar.selectbox( + "ANNO RIFERIMENTO", (["2023","2024", "2025", "2026"]), index=1 + ) + self.make_sidebar() + self.DEBUGWARNINGS = False + self.TOLLERANZAZERO = False + + self.STATUS = st.sidebar.empty() + self.STATUS2 = st.sidebar.empty() + self.STATUS3 = st.sidebar.empty() + + try: + self.ERRORDICT = valori.ERRORDICT[self.ANNO_RIFERIMENTO] + self.ERROR_ICONS = valori.ERROR_ICONS + except Exception as e: + self.STATUS.error( + f"Non e' stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + if self.TOLLERANZAZERO or self.DEBUGWARNINGS: + st.error("Elaborazione interrotta") + st.stop() + + self.make_form() + + # Use the unified file upload method instead of the separate ones + self.upload_all_files() + self.choose_checks() + + def get_version(self) -> str: + return "Interface 1.0.0" + + def make_sidebar(self): + """ + Create the sidebar interface with configuration options. + + Creates checkboxes and radio buttons for various settings including: + - Integrity message display + - Date string conversion + - Processing interruption settings + - Constants display + - General debug mode + """ + # st.sidebar.info("Einstellungen") + # expander = st.sidebar.expander("Impostazioni generali") + with st.sidebar.expander("Configurazione"): + + self.MOSTRAERRORIINTEGRITA = st.checkbox( + "Mostra messaggi integrita' strutturale", True + ) + self.CONVERTIDATESTRINGHE = st.checkbox( + "Convertire le date in stringhe", True + ) + self.INTERRUZIONE = st.radio( + "Interrompere elaborazione se...", + ("Non interrompere", "Warnings", "Tolleranza zero"), + ) + + if self.INTERRUZIONE == "Warnings": + self.DEBUGWARNINGS = True + elif self.INTERRUZIONE == "Tolleranza zero": + self.TOLLERANZAZERO = True + + self.MOSTRACOSTANTI = st.checkbox("Mostra costanti per anno riferimento") + if self.MOSTRACOSTANTI: + try: + st.info(self.valori.COSTANTI[self.ANNO_RIFERIMENTO]) + except: + st.error("Impossibile mostrare costanti") + + self.DEBUGGENERAL = st.checkbox("Debug generale") + + def get_file_list(self): + """ + Create a file uploader for selecting multiple Excel files. + """ + self.uploaded_files = st.file_uploader( + "Excel Dateien auswaehlen", accept_multiple_files=True + ) + # st.write(self.filelist) + + def make_expander(self, title1, title2, count, dftemp): + """ + Create an expandable section to display data results. + + Args: + title1 (str): Primary title for the expander + title2 (str): Secondary title/description + count (int): Number of occurrences found + dftemp (pd.DataFrame): DataFrame containing the results to display + """ + with st.expander(f"Trovate **{count}** occorrenze per {title1}"): + st.info(title2) + # st.write(dftemp) + # Create a grid display of the sorted dataframe + self.make_grid( + dftemp.sort_values(by=["Cognome", "Nome"]), + title1, + ) + + self.download_excel_file( + dftemp.sort_values(by=["Cognome", "Nome"]), + f"{title1}.xlsx", + ) + + def make_form(self) -> None: + """ + Create a sidebar form with a submit button. + + The form includes a submit button that triggers the start of data processing and error checking. + """ + frm = st.sidebar.form("Auswahl", clear_on_submit=True) + with frm: + # This solution is somewhat awkward, but we want to move the expanders outside of the form + # so that we can use the button for download + self.submit = frm.form_submit_button("Iniziare elaborazione e controlli") + +# def choose_files(self, c1) -> None: +# """Allow users to upload multiple Excel files for checking.""" +# self.uploaded_files: List[FileUploadBase] = c1.file_uploader( +# "SCEGLIERE FILE EXCEL DA CONTROLLARE", accept_multiple_files=True +# ) + +# def choose_allegato666(self, c2) -> None: +# """ +# Allow users to upload the Allegato 666 file for checking.# + +# Args: +# None + + # Returns: + # None + # """ + # self.uploaded_allegato666: FileUploadBase = c2.file_uploader( + # "CARICARE ALLEGATO 666", accept_multiple_files=False + # ) + + def choose_checks(self) -> None: + """ + Creates a dynamic list of checkboxes based on a dictionary containing error names and descriptions. + Updates the 'checks' dictionary with the selected checkboxes. + + :return: None + """ + # Initialize the checks dictionary + self.checks: Dict[str, bool] = {} + + # Create an expander to hold the checkboxes + expndr = st.expander( + "SELEZIONE CONTROLLI DA ESEGUIRE (i controlli sull'integrità dei dati vengono eseguiti sempre)", + expanded=False, + ) + + try: + with expndr: + # Create a 'Select All' checkbox + select_all = st.checkbox( + "🗂️ Selezionare/deselezionare tutti i controlli", + value=True, + key="select_all_checks", + ) + + # Create 4 columns to distribute checkboxes evenly + columns = expndr.columns(4) + + # Iterate over the ERRORDICT items with enumeration + for idx, (error_key, error_description) in enumerate( + self.ERRORDICT.items() + ): + # Determine the appropriate column for the current checkbox + col = columns[idx % 4] + + # Retrieve the corresponding icon, default to a warning emoji if not found + icon = self.ERROR_ICONS.get(error_key, "⚠️") + + # Create the checkbox within the determined column + self.checks[error_key] = col.checkbox( + label=f"{icon} {error_description}", + value=select_all, + key=f"{error_key}_checkbox", + ) + + except Exception as e: + with expndr: + # Display a warning message if an error occurs + st.warning( + f"Non è stato possibile creare la lista dei controlli. Forse non sono stati definiti per l'anno {self.ANNO_RIFERIMENTO}? Errore: {e}" + ) + + # Optionally display an error and stop execution based on flags + if getattr(self, "TOLLERANZAZERO", False) or getattr( + self, "DEBUGWARNINGS", False + ): + st.error("Elaborazione interrotta") + st.stop() + + def make_tabs(self) -> None: + """ + Create the main navigation tabs for the application. + + Creates three tabs: + - Data Integrity + - Errors and Inconsistencies + - Final Tables + """ + self.TAB1, self.TAB2, self.TAB3 = st.tabs( + [ + "INTEGRITÀ DATI", + "ERRORI e INCONGRUENZE RISCONTRATI", + "TABELLE FINALI", + ] + ) + + @st.fragment() + def buildGrid(self, data: pd.DataFrame): + """ + Build a grid configuration for displaying tabular data. + + Args: + data (pd.DataFrame): The DataFrame to be displayed in the grid + + Returns: + dict: Grid options configuration for AG-Grid + """ + gb = GridOptionsBuilder.from_dataframe(data) + # Configure pagination settings + gb.configure_pagination(paginationAutoPageSize=True, paginationPageSize=20) + # Configure side bar for column filtering and selection + gb.configure_side_bar() + # Configure selection mode to multiple rows with checkbox + gb.configure_selection(selection_mode="multiple", use_checkbox=True) + # Configure default column properties + gb.configure_default_column( + groupable=True, + value=True, + enableRowGroup=True, + aggFunc="count", + editable=True, + ) + + gridOptions = gb.build() + return gridOptions + + @st.fragment() + def make_grid(self, dff: pd.DataFrame, k: str) -> None: + """ + Create and display an interactive data grid. + + Args: + dff (pd.DataFrame): DataFrame to be displayed in the grid + k (str): Unique key identifier for the grid component + """ + # st.write(dff) + # Drop unnecessary columns from the DataFrame + helper = helpers() + dff = helper.drop_columns(dff, self.ERRORDICT) + # st.write(dff) + # Append a new row with "filename" set to an empty string + new_row_df = pd.DataFrame({"filename": " "}, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Append another new row with "filename" set to the current date + new_row_data = { + "filename": "file generato in data: " + date.today().strftime("%d/%m/%Y") + } + new_row_df = pd.DataFrame(new_row_data, index=[0]) + dff = pd.concat([dff, new_row_df], ignore_index=True) + + # Build the grid options object + gridOptions = self.buildGrid(dff) + + # Display the grid using AgGrid + AgGrid(dff, gridOptions=gridOptions, enable_enterprise_modules=True, key=k) + + @st.fragment() + def download_excel_file(self, dftosave: pd.DataFrame, nome_file: str, flag: Optional[str] = None) -> None: + """ + Create and provide a download button for an Excel file. + + Args: + dftosave (pd.DataFrame): DataFrame to be saved as Excel + nome_file (str): Name of the output file + flag (Optional[str]): Flag to control column handling ('mantieniColonneErrore' to keep error columns) + + Raises: + KeyError: If required columns are missing from the DataFrame + ValueError: If there are invalid or incompatible values + Exception: For other unexpected errors + """ + try: + # Step 1: Remove 'Colonna_L_da_cancellare_dopo' if it exists + dftosave = dftosave.drop( + columns=["Colonna_L_da_cancellare_dopo"], errors="ignore" + ) + + # Step 2: Add timestamp to the file name + timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + nome_file = f"{timestamp}_{nome_file}" + + # Step 3: Drop columns based on the flag + if flag == "mantieniColonneErrore": + pass + else: + dftosave = helper.drop_columns(dftosave, self.ERRORDICT) + + # Step 4: Initialize an in-memory buffer + buffer = BytesIO() + + # Step 5: Write DataFrame to the buffer using ExcelWriter + with pd.ExcelWriter(buffer, engine="xlsxwriter") as writer: + dftosave.to_excel(writer, sheet_name="risultato", index=False) + workbook = writer.book + worksheet = writer.sheets["risultato"] + + # Step 6: Dynamically set column widths based on content + for idx, col in enumerate(dftosave.columns): + # Calculate the maximum length of the column content + max_length = dftosave[col].astype(str).map(len).max() + max_length = max(max_length, len(col)) + 2 # Adding extra space + worksheet.set_column(idx, idx, max_length) + + # Step 7: Retrieve the Excel file bytes from the buffer + buffer.seek(0) + file_bytes = buffer.read() + + # Step 8: Add an icon to the download button using an emoji + ste.download_button( + label="📥 Download dei dati nel formato Excel", + data=file_bytes, + file_name=nome_file, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ) + + except KeyError as ke: + st.error(f"Chiave mancante nel DataFrame: {ke}") + st.stop() # Stop further execution + + except ValueError as ve: + st.error(f"Valore non valido o incompatibile: {ve}") + st.stop() # Stop further execution + + except Exception as e: + st.error(f"Si è verificato un errore inaspettato: {e}") + st.stop() # Stop further execution + + def upload_all_files(self) -> None: + """ + Allow users to upload all Excel files at once, automatically identifying the Allegato 666 file. + + This method uploads multiple files and then: + - Assigns files with "666" in their name to self.uploaded_allegato666 (only one such file is expected) + - Assigns all other files to self.uploaded_files + """ + # Upload all files at once + all_uploaded_files = st.file_uploader( + "SCEGLIERE TUTTI I FILE EXCEL (incluso Allegato 666)", + accept_multiple_files=True + ) + + # Initialize as empty lists + self.uploaded_files = [] + self.uploaded_allegato666 = None + + # Find Allegato 666 file and separate it from other files + allegato_666_files = [] + other_files = [] + + if all_uploaded_files: + for file in all_uploaded_files: + if "666" in file.name: + allegato_666_files.append(file) + else: + other_files.append(file) + + # Assign the regular files to self.uploaded_files + self.uploaded_files = other_files + + # Handle Allegato 666 file(s) and display messages using columns + if len(allegato_666_files) > 0 or len(other_files) > 0: + col1, col2 = st.columns(2) + + # Handle Allegato 666 file(s) + if len(allegato_666_files) == 1: + self.uploaded_allegato666 = allegato_666_files[0] + col1.success(f"Allegato 666 identificato: {self.uploaded_allegato666.name}") + elif len(allegato_666_files) > 1: + col1.error("Sono stati caricati più file contenenti '666' nel nome. È necessario un solo file Allegato 666.") + self.uploaded_allegato666 = None + + # Display count of regular files + if len(other_files) > 0: + col2.info(f"Caricati {len(other_files)} file Excel aggiuntivi") diff --git a/utilities/reportmaker.py b/utilities/reportmaker.py new file mode 100644 index 0000000000000000000000000000000000000000..5714d0be11bf0840961193414f8db8ca9fee058c --- /dev/null +++ b/utilities/reportmaker.py @@ -0,0 +1,564 @@ +from reportlab.lib.pagesizes import A4 +from reportlab.lib import colors +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.lib.units import inch, cm +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.pdfgen import canvas +from reportlab.platypus import Image + +import streamlit as st +import pandas as pd +from io import BytesIO +import xlsxwriter +from datetime import date, datetime +from st_aggrid import AgGrid +from st_aggrid.grid_options_builder import GridOptionsBuilder + +from .helpertools_TM import helpers + + +class ReportGenerator: + + def __init__(self, processor, trova_errori, interface, no_zero=None): + """Initialize ReportGenerator with required components. + + processor: Handles data processing and error collection + trova_errori: Contains error detection logic and dataframes + interface: Handles UI interactions and grid displays + no_zero: Flag for handling zero values + """ + self.df = trova_errori.df + self.df_bambini = trova_errori.df_bambini_che_impediscono_controllo_superamento_ore + + self.df_calcolo_666 = trova_errori.df_calcolo_666 + self.dffinal = trova_errori.dffinal + self.processor = processor + self.no_zero = no_zero + self.interface = interface + self.trova_errori = trova_errori + + self.ERRORDICT = trova_errori.ERRORDICT + self.helper = helpers(interface,self.ERRORDICT) + + def get_version(self): + return "ReportGenerator v1.0.1" + + @st.fragment() + def display_final_table(self) -> None: + """ + Displays the final table with all data and a separate table for errors only. + + This method creates two expanders: one for displaying all data in a grid format, + and another for showing only records that contain errors. It also provides options + to download these tables as Excel files. + + Args: + None + + Returns: + None + """ + # Display the final table with all data + no_zero = self.no_zero # Assuming this is defined somewhere else in the code. + # Create expander for full data table + # This section shows all records, including those without errors + expndr = st.expander("TABELLA FINALE ELABORATA - TUTTI I DATI") + with expndr: + # Enable Excel download of complete dataset + # Sort by surname and name for better readability + self.interface.download_excel_file( + self.df.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_TuttiDati.xlsx", + 'mantieniColonneErrore' + ) + + # Configure and display interactive grid with all records + # Enable enterprise features for better user interaction + gridOptions = self.interface.buildGrid(self.df.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.df.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + ) + + # Display the table with only errors + # Create expander for error-only table + # This section filters and shows only records with detected errors + expndr = st.expander("TABELLA FINALE ELABORATA - SOLO ERRORI") + with expndr: + # Filter data to show only records with errors + self.dffinal = self.helper.make_df_solo_errori(self.df) + + # Provide download option for the errors-only table + self.interface.download_excel_file( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + "TabellaFinaleElaborata_SoloErrori.xlsx", + "mantieniColonneErrore" + ) + + # Display the errors-only table in a grid format + gridOptions = self.interface.buildGrid(self.dffinal.sort_values(by=["Cognome", "Nome"])) + AgGrid( + self.dffinal.sort_values(by=["Cognome", "Nome"]), + gridOptions=gridOptions, + enable_enterprise_modules=True, + key="tabfinalex" + ) + + # Save the errors-only table to an Excel file + try: + self.dffinal.to_excel("storico.xlsx") + st.success("Salvato file storico: OK") + except Exception as e: + st.error(f"ERRORE salvataggio file storico: errore({e})") + + def genera_report(self) -> None: + """ + Generates detailed reports in Excel and PDF formats and provides download options via Streamlit. + + This method filters errors, computes unique children and municipalities, and generates + Excel and PDF reports if errors are present. It handles various exceptions that may occur + during the report generation process. + + Args: + None + + Returns: + None + """ + # Generate detailed reports in Excel and PDF formats + try: + # Filter out specific errors and get current error state + error_keys, errors_present = self._filter_errors(excluded_error="errMassimo543") + + # Early return if no checks are needed + if not error_keys: + st.warning("Nessun controllo da eseguire.") + return + + # Calculate statistics about the dataset + nr_bambini = self._compute_unique_children() + nr_comuni = self._compute_unique_gemeinden() + + # Early return if no errors were found + if not errors_present: + st.info("Nessun errore rilevato nei controlli selezionati.") + return + + # Generate reports and provide download options + try: + excel_data = self._generate_excel_report(nr_bambini, nr_comuni, errors_present) + except (xlsxwriter.exceptions.FileCreateError, PermissionError) as e: + st.error(f"File access error: {str(e)}") + st.stop() + except ValueError as ve: + st.error(f"Invalid data format: {str(ve)}") + st.stop() + except KeyError as ke: + st.error(f"Missing required column: {str(ke)}") + st.stop() + self._provide_downloads(excel_data) + st.success("Generato file riassunto analisi") + + except KeyError as ke: + # Handle missing or invalid data structure errors + st.error(f"Chiave mancante o struttura dati non valida: {ke}") + st.stop() + except ValueError as ve: + st.error(f"Problema di tipo o formato dati: {ve}") + st.stop() + except FileNotFoundError as fnf: + st.error(f"File di riferimento non trovato: {fnf}") + except PermissionError as pe: + st.error(f"Permessi insufficienti per accedere al file: {pe}") + except Exception as e: + st.error(f"Errore imprevisto durante la generazione del report: {e}") + st.stop() + + def _filter_errors(self, excluded_error: str): + """ + Excludes a specific error from the error dictionary and computes present errors. + + Args: + excluded_error (str): The error key to be excluded from the error dictionary. + + Returns: + Tuple[List[str], Dict[str, int]]: Filtered error keys and errors with counts > 0. + """ + # Exclude a specific error and compute present errors + # Create list of error keys excluding specified error + error_keys = [k for k in self.ERRORDICT.keys() if k != excluded_error] + if not error_keys: + return error_keys, {} + + # Calculate error occurrences and filter out zeros + error_counts = self.df[error_keys].sum() + errors_present = error_counts[error_counts > 0].to_dict() + return error_keys, errors_present + + def _compute_unique_children(self) -> int: + """ + Computes the number of unique children based on 'Codice fiscale'. + + Args: + None + + Returns: + int: The number of unique children. + """ + # Compute the number of unique children + return self.df["Codice fiscale"].nunique() + + def _compute_unique_gemeinden(self) -> int: + """ + Computes the number of unique municipalities based on 'Com_code'. + + Args: + None + + Returns: + int: The number of unique municipalities. + """ + # Compute the number of unique municipalities + return self.df["Com_code"].nunique() + + def _generate_excel_report(self, nr_bambini: int, nr_comuni: int, errors_present: dict) -> bytes: + """ + Generates the Excel report and returns the binary data. + + Args: + nr_bambini (int): Number of unique children. + nr_comuni (int): Number of unique municipalities. + errors_present (dict): Dictionary of errors with their counts. + + Returns: + bytes: The binary data of the generated Excel report. + """ + # Generate the Excel report and return the binary data + excel_buffer = BytesIO() + with xlsxwriter.Workbook(excel_buffer) as workbook: + worksheet = workbook.add_worksheet("Riassunto") + try: + self._write_excel_summary(worksheet, nr_bambini, nr_comuni, errors_present, workbook) + except: + st.error("Error during _write_excel_summary") + try: + self._write_excel_detailed_sections(worksheet, errors_present, workbook) + except: + st.error("Error during _write_excel_detailed") + return excel_buffer.getvalue() + + def _write_excel_summary(self, worksheet, nr_bambini: int, nr_comuni: int, errors_present: dict, workbook): + """ + Writes the summary section of the Excel report. + + Args: + worksheet: The worksheet object to write the summary to. + nr_bambini (int): Number of unique children. + nr_comuni (int): Number of unique municipalities. + errors_present (dict): Dictionary of errors with their counts. + workbook: The workbook object to format the cells. + + Returns: + None + """ + # Write the summary section of the Excel report + # Define cell formats for different sections + bold_format = workbook.add_format({'bold': True, 'font_size': 12}) + bold_format2 = workbook.add_format({'bold': True, 'font_size': 11}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + title_format = workbook.add_format({'bold': True, 'font_size': 18}) + + row, col = 3, 0 # Starting from row 1 as row 0 is typically reserved + + # Write report title and basic statistics + try: + worksheet.write(row, col, "Riassunto analisi resoconti Tagesmuetter", title_format) + worksheet.set_row(row, 30) # Set row height to 30 + row += 4 + except xlsxwriter.exceptions.XlsxWriterException as xlse: + st.error(f"Worksheet write error: {str(xlse)}") + raise # Re-raise to abort the process + + try: + # Number of children + worksheet.write(row, col, f"Sono stati elaborati i dati di {nr_bambini} bambini in {nr_comuni} comuni") + row += 2 + except: + st.error("Error during Sono stati elaborati i dati di {nr_bambini} bambini in {nr_comuni} comuni") + + # Document all errors found in the analysis + try: + for error_key, count in errors_present.items(): + if error_key not in self.df.columns: + raise KeyError(f"Error column {error_key} not found in dataframe") + + if error_key not in self.ERRORDICT: + raise ValueError(f"Undocumented error code: {error_key}") + + error_description = self.ERRORDICT[error_key] + worksheet.write( + row, col, + f"Trovate {int(count)} occorrenze per il controllo {error_description}") + row += 1 + row += 2 # Blank row + except: + st.error("Error during Document all errors found in the analysis") + + # Document processing errors from file handling + try: + for key in self.processor.errori.keys(): + #st.write(key) + worksheet.write( + row, col, + f"Errori {key}:" + (" (file non usati)" if key == "critici" else ""), + bold_format + ) + row += 1 + for filename in self.processor.errori[key]: + #st.write(filename) + worksheet.write( + row, col+1, + filename.split('/', 1)[1] if '/' in filename else filename, + #filename, #.split('/', 1)[1], + ) + + for error in self.processor.errori[key][filename]: + #st.write("entered error") + #st.write(error) + worksheet.write( + row, col+2, + error, + ) + row += 1 + row += 1 + row += 3 + except Exception as e: + st.error("Error during Document processing errors from file handling: " + str(e)) + + # Handle special cases: children without hour control + try: + if not self.df_bambini.empty: + worksheet.write( + row, col, + "Bambini per i quali non e' possibile eseguire il controllo superamento ore nel periodo contrattuale", + bold_format + ) + row += 1 + + # Write column headers + for header_col, header in enumerate(self.df_bambini.columns): + worksheet.write(row, header_col, header, header_format) + row += 1 + + # Set fixed column widths + worksheet.set_column(0, len(self.df_bambini.columns)-1, 25) + + # Write data rows + for _, r in self.df_bambini.iterrows(): + for header_col, header in enumerate(self.df_bambini.columns): + value = r.get(header, "") + if isinstance(value, pd.Timestamp): + value = value.strftime("%d/%m/%Y") + worksheet.write(row, header_col, value) + row += 1 + row += 3 # Blank rows + except: + st.error("Error during Handle special cases: children without hour control") + + # Document discrepancies in attachment 666 + if not self.df_calcolo_666.empty: + worksheet.set_column(0, len(self.df_calcolo_666.columns)-1, 25) + + filtered_df_ore = self.df_calcolo_666[self.df_calcolo_666['Confronto ore'] == False] + filtered_df_bambini = self.df_calcolo_666[self.df_calcolo_666['Confronto bambini'] == False] + + if not filtered_df_ore.empty: + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero delle ore per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Ore di servizio allegato 666", "Ore di assistenza report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_ore.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Ore di servizio allegato 666", "")) + worksheet.write(row, col + 3, r.get("Ore di assistenza report Comuni", "")) + row += 1 + row +=1 # Blank rows + + if not filtered_df_bambini.empty: + worksheet.write( + row, col, + "Riscontrate incongruenze nel numero bambini per l'allegato 666", bold_format) + row += 2 + + # Define headers + headers = ["Comune provenienza bambino", "Numero utenti allegato 666", "Numero bambini report Comuni"] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for _, r in filtered_df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Comune provenienza bambino", "")) + worksheet.write(row, col + 2, r.get("Numero utenti allegato 666", "")) + worksheet.write(row, col + 3, r.get("Numero bambini report Comuni", "")) + row += 1 + + def _write_excel_detailed_sections(self, worksheet, errors_present: dict, workbook): + """ + Writes detailed sections per error in the Excel report. + + Args: + worksheet: The worksheet object to write the detailed sections to. + errors_present (dict): Dictionary of errors with their counts. + workbook: The workbook object to format the cells. + + Returns: + None + """ + # Write detailed sections per error in the Excel report + title_format2 = workbook.add_format({'bold': True, 'font_size': 12}) + header_format = workbook.add_format({'bold': True, 'bg_color': '#D7E4BC'}) + date_format = workbook.add_format({'num_format': 'dd/mm/yyyy'}) + summary_format = workbook.add_format({'italic': False, 'font_size': 10}) + + row, col = worksheet.dim_rowmax, 0 + row += 4 + + for error_key, count in errors_present.items(): + error_description = self.ERRORDICT.get(error_key, error_key) + worksheet.write(row, col, error_description, title_format2) + row += 2 + + # Headers for detailed sections + headers = [ + "Cognome", + "Nome", + "Codice fiscale", + "Data di nascita", + "Comune", + "Data inizio contratto", + "Data fine contratto", + ] + for i, header in enumerate(headers): + worksheet.write(row, col + i + 1, header, header_format) + row += 1 + + for header_col, header in enumerate(headers, start=1): + max_length = max( + self.df[header].astype(str).map(len).max() + if header in self.df.columns else 0, + len(header) + ) + 2 + worksheet.set_column(col + header_col, col + header_col, max_length + 5) + + df_bambini = self.df[self.df[error_key] == True].sort_values(by=["Cognome", "Nome"]) + + for _, r in df_bambini.iterrows(): + worksheet.write(row, col + 1, r.get("Cognome", "")) + worksheet.write(row, col + 2, r.get("Nome", "")) + worksheet.write(row, col + 3, r.get("Codice fiscale", "")) + + data_nascita = r.get("Data di nascita", "") + if pd.notnull(data_nascita) and isinstance(data_nascita, pd.Timestamp): + worksheet.write_datetime(row, col + 4, data_nascita, date_format) + else: + worksheet.write(row, col + 4, str(data_nascita)) + + worksheet.write(row, col + 5, r.get("Comune", "")) + + data_inizio = r.get("Data inizio contratto (o data inizio assistenza se diversa)", "") + if pd.notnull(data_inizio) and isinstance(data_inizio, pd.Timestamp): + worksheet.write_datetime(row, col + 6, data_inizio, date_format) + else: + worksheet.write(row, col + 6, str(data_inizio)) + + data_fine = r.get("Data fine contratto (o data fine assistenza se diversa)", "") + if pd.notnull(data_fine) and isinstance(data_fine, pd.Timestamp): + worksheet.write_datetime(row, col + 7, data_fine, date_format) + else: + worksheet.write(row, col + 7, str(data_fine)) + + row += 1 + + # Add summary line below the table + row += 1 + worksheet.write(row, col, "Riepilogo:", summary_format) + #row += 1 + + # Collect all names and communes into a single summary line + summary_entries = [] + for _, r in df_bambini.iterrows(): + # Capitalize each part of potentially compound names + cognome_parts = [part.capitalize() for part in r.get("Cognome", "").split()] + nome_parts = [part.capitalize() for part in r.get("Nome", "").split()] + + cognome = " ".join(cognome_parts).rstrip() + nome = " ".join(nome_parts).rstrip() + comune = r.get("Comune", "").rstrip() + summary_entries.append(f"{cognome} {nome} ({comune})") + + # Join all entries with comma separators and write as a single line + summary_line = ", ".join(summary_entries) + worksheet.write(row, col + 1, summary_line, summary_format) + row += 1 + + row += 3 + + def _prepare_additional_df(self) -> pd.DataFrame: + """ + Prepares the additional DataFrame for the PDF report by renaming and dropping columns. + + Args: + None + + Returns: + pd.DataFrame: The prepared additional DataFrame. + """ + # Prepare the additional DataFrame for the PDF report + additional_df = self.df_bambini.copy() + + column_list = list(additional_df.columns) + column_list[3] = 'Data Inizio Contratto' + column_list[4] = 'Data Fine Contratto' + additional_df.columns = column_list + + position_to_delete = 5 # Adjust based on actual column index + if position_to_delete < len(additional_df.columns): + column_name = additional_df.columns[position_to_delete] + additional_df.drop(columns=column_name, inplace=True) + + return additional_df + + @st.fragment() + def _provide_downloads(self, excel_data: bytes): #, pdf_data: bytes): + """ + Provides download buttons for the generated Excel and PDF reports. + + Args: + excel_data (bytes): The binary data of the generated Excel report. + # pdf_data (bytes): The binary data of the generated PDF report. + + Returns: + None + """ + # Provide download buttons for the generated Excel and PDF reports + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + excel_file_name = f"riassuntoAutomatico_{timestamp}.xlsx" + + col1, col2 = st.columns(2) + with col1: + st.download_button( + label="📥 Scarica report riassuntivo dell'analisi in formato Excel", + data=excel_data, + file_name=excel_file_name, + mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + key="fileRiassuntoExcel", + ) diff --git a/utilities/valoriEtErrori.py b/utilities/valoriEtErrori.py new file mode 100644 index 0000000000000000000000000000000000000000..822a03667ef8be372bc0c6a6386cb9e0d73c18f4 --- /dev/null +++ b/utilities/valoriEtErrori.py @@ -0,0 +1,125 @@ +import pandas as pd +from typing import Optional, List, Dict, Any + +class valoriEtErrori: + + COSTANTI2023 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2021", format="%d.%m.%Y" + ), + } + + COSTANTI2024 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2022", format="%d.%m.%Y" + ), + } + + COSTANTI2025 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2023", format="%d.%m.%Y" + ), + } + COSTANTI2026 = { + # usiamo un valore dummy giusto per averlo + # cosi' non dobbiamo modificare il programma + "KONTROLLEKINDERGARTEN_DATANASCITA_2": pd.to_datetime( + "01.01.2024", format="%d.%m.%Y" + ), + } + + COSTANTI = {"2023": COSTANTI2023, "2024": COSTANTI2024, "2025": COSTANTI2025, "2026": COSTANTI2026} + + + ERRORDICT2023 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + ERRORDICT2024 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + ERRORDICT2025 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + ERRORDICT2026 = { + "errCodFisc1": "Formato codice fiscale", # ok + "errCodFisc2": "Data nascita per codice fiscale", # ok + "errAgeChild": "Età bambino inizio contratto", # ok + "errInizioMinoreFine": "Incongruenza date contratto", # ok + "errFineAssistenzaMax4Anni": "Età bambino fine contratto", + "errKindergarten": "Scuola dell'infanzia", # ok + "errGesamtstundenVertragszeitraum": "Superamento ore nel periodo contrattuale ", # ok + "errSuperatoOreMassime1920": "Ore anno > 1920", # ok + "errBambinoInPiuComuni": "Bambini presenti in più comuni", # ok + "errPresentiAnnotazioni": "Bambini con annotazioni", + "errOreRendicontateZero": "Ore rendicontate uguali a zero", # ok + "errCalcoloNumeroBimbi": "Tabella ore e bambini per comune", # ok + #"errNomeComuneTagesmutter": "Tabella con comuni Tagesmutter non ufficiali", + "errDateAnnoRiferimento": "Date inizio o fine incongruenti con anno riferimento", + } + + + ERRORDICT = {"2023": ERRORDICT2023, "2024": ERRORDICT2024, "2025": ERRORDICT2025, "2026": ERRORDICT2026} + + # Define a mapping from error keys to relevant emojis + ERROR_ICONS: Dict[str, str] = { + "errCodFisc1": "🧾", # Receipt + "errCodFisc2": "📅", # Calendar + "errAgeChild": "👶", # Baby + "errInizioMinoreFine": "🔄", # Repeat + "errFineAssistenzaMax4Anni": "⏳", # Hourglass + "errKindergarten": "🏫", # School + "errGesamtstundenVertragszeitraum": "⏰", # Alarm Clock + "errSuperatoOreMassime1920": "📊", # Bar Chart + "errBambinoInPiuComuni": "📍", # Location Pin + "errPresentiAnnotazioni": "📝", # Memo + "errOreRendicontateZero": "❌", # Cross Mark + "errCalcoloNumeroBimbi": "📋", # Clipboard + #"errNomeComuneTagesmutter": "🏠", # House + "errDateAnnoRiferimento": "📆", # Tear-Off Calendar + } \ No newline at end of file