PARAMETRES

# import
import os
import json
import pandas as pd
import numpy as np
import copy
import plotly.graph_objects as go
from datetime import datetime
import copy

from openfisca_core.simulation_builder import SimulationBuilder
from leximpact_survey_scenario.leximpact_tax_and_benefit_system import leximpact_tbs
# niveaux de revenus (en pss ou en €)
x_min_enpss = 0
x_max_enpss = 10
x_pas_enpss = 0.25
pss_mensuel = 3864

x_min = x_min_enpss * pss_mensuel
x_max = x_max_enpss * pss_mensuel
x_pas = x_pas_enpss * pss_mensuel
x_range = np.arange(x_min, x_max * 12 + 12, x_pas * 12)

# for x in x_range:
#    print (x)

x_range_length = len(x_range)
# print(x_range_length)
# chemin vers les cas-types
path_cas_types = os.path.join(os.getcwd(), "cas_types")
# liste des cotisations
liste_cotisations = [
    # revenus
    "salaire_de_base",
    "traitement_indiciaire_brut",
    # cotisations salariales (contributives)
    # prive
    "agirc_arrco_salarie",
    "apec_salarie",
    "contribution_equilibre_general_salarie",
    "contribution_equilibre_technique_salarie",
    "vieillesse_deplafonnee_salarie",
    "vieillesse_plafonnee_salarie",
    # public
    "ircantec_salarie",
    "pension_salarie",
    "rafp_salarie",
    # cotisations salariales (non contributives)
    "mmid_salarie",
    # cotisations patronales (contributives)
    "ags",
    "agirc_arrco_employeur",
    "apec_employeur",
    "chomage_employeur",
    "contribution_equilibre_general_employeur",
    "contribution_equilibre_technique_employeur",
    "vieillesse_deplafonnee_employeur",
    "vieillesse_plafonnee_employeur",
    "fonds_emploi_hospitalier",
    "ircantec_employeur",
    "pension_employeur",
    "rafp_employeur",
    # cotisations patronales (non contributives)
    "ati_atiacl",
    "penibilite",
    "accident_du_travail",
    "contribution_solidarite_autonomie",
    "famille",
    "mmid_employeur",
    "taxe_salaires",
    "forfait_social",
    # contributions
    "csg_deductible_salaire",
    "csg_imposable_salaire",
    "crds_salaire",
    "fnal_contribution",
    "versement_transport",
    "taxe_apprentissage",
    "formation_professionnelle",
]
# liste des cas-types

# prive
liste_cas_types_prive = [
    "cot_01_salarie_prive_non_cadre.json",
    "cot_02_salarie_prive_cadre.json",
]

# public
liste_cas_types_public = [
    "cot_03_salarie_public_titulaire_etat.json",
    "cot_04_salarie_public_titulaire_militaire.json",
    "cot_05_salarie_public_titulaire_territoriale.json",
    "cot_06_salarie_public_titulaire_hospitaliere.json",
    "cot_07_salarie_public_non_titulaire.json",
]

FONCTIONS

def calculer_cotisations(liste_cas_types, liste_cotisations, revenu):
    for i_cas_type in range(len(liste_cas_types)):
        # importer le cas-type
        cas_types = os.path.join(path_cas_types, liste_cas_types[i_cas_type])
        with open(cas_types) as f:
            temp = json.load(f)
            if temp.get("sliders"):
                del temp["sliders"]
            del temp["description"], temp["linked_variables"], temp["title"]

        # duplication du cas type en fonction du revenus
        list_cas_types = list()

        # boucle revenus
        for i in x_range:
            # print(i)
            temp2 = copy.deepcopy(temp)
            temp2["individus"]["Adulte 1"][revenu] = {
                "2023": i,
                "2024": i,
                "2025": i,
            }
            list_cas_types.append(temp2)
        data_frame = pd.DataFrame(list_cas_types)

        # cas-type
        cas_type = dict(
            data_frame.iloc[2][["familles", "foyers_fiscaux", "individus", "menages"]]
        )

        # pour chaque niveau de revenus on calcul le détail
        donnees = pd.DataFrame()
        for i in range(x_range_length):
            cas_type = dict(
                data_frame.iloc[i][
                    ["familles", "foyers_fiscaux", "individus", "menages"]
                ]
            )
            simulation = SimulationBuilder()
            simulation = simulation.build_from_entities(leximpact_tbs, cas_type)
            indiv = dict()
            for variable in liste_cotisations:
                indiv[variable] = [simulation.calculate(variable, "2025-01")[0]]
            donnees = pd.concat([donnees, pd.DataFrame(indiv)], axis=0)

            # cotisations en positif
            donnees = donnees.abs()

            # colonne pss
            donnees["pss"] = donnees.loc[:, revenu] / pss_mensuel

            # total des cotisations sariales et employeur
            donnees["total_cotis_salarie"] = 0
            for j in np.arange(0, len(donnees.columns) - 1, 1):
                if "salarie" in donnees.columns[j]:
                    if donnees.columns[j] in donnees.columns:
                        donnees["total_cotis_salarie"] = (
                            donnees["total_cotis_salarie"] + donnees[donnees.columns[j]]
                        )

            autres_cotis_salariales = [
                "csg_deductible_salaire",
                "csg_imposable_salaire",
                "crds_salaire",
            ]
            for i_cotis_sal in np.arange(0, len(autres_cotis_salariales) - 1, 1):
                if autres_cotis_salariales[i_cotis_sal] in donnees.columns:
                    donnees["total_cotis_salarie"] = (
                        donnees["total_cotis_salarie"]
                        + donnees[autres_cotis_salariales[i_cotis_sal]]
                    )

            # employeur
            donnees["total_cotis_employeur"] = 0
            for j in np.arange(0, len(donnees.columns) - 1, 1):
                if "employeur" in donnees.columns[j]:
                    if donnees.columns[j] in donnees.columns:
                        donnees["total_cotis_employeur"] = (
                            donnees["total_cotis_employeur"]
                            + donnees[donnees.columns[j]]
                        )

            autres_cotis_patronales = [
                "forfait_social",
                "ags",
                "contribution_solidarite_autonomie",
                "famille",
                "accident_du_travail",
                "fnal_contribution",
                "taxe_apprentissage",
                "formation_professionnelle",
            ]
            for i_cotis_pat in np.arange(0, len(autres_cotis_patronales) - 1, 1):
                if autres_cotis_patronales[i_cotis_pat] in donnees.columns:
                    donnees["total_cotis_employeur"] = (
                        donnees["total_cotis_employeur"]
                        + donnees[autres_cotis_patronales[i_cotis_pat]]
                    )

            # cotisations totales
            donnees["total_cotis"] = (
                donnees["total_cotis_salarie"] + donnees["total_cotis_employeur"]
            )

            # ordre des colonnes
            col = donnees.pop("total_cotis_salarie")
            donnees.insert(0, col.name, col)

            col = donnees.pop("total_cotis_employeur")
            donnees.insert(0, col.name, col)

            col = donnees.pop("total_cotis")
            donnees.insert(0, col.name, col)

            col = donnees.pop(revenu)
            donnees.insert(0, col.name, col)

            col = donnees.pop("pss")
            donnees.insert(0, col.name, col)

        # supprimer les colonnes de zéros
        donnees = donnees.loc[:, donnees.any()]

        # arrondir
        # donnees = round(donnees, 4)

        # enregistrer donnees cas-type
        # print('enregistrer donnees')
        globals()["donnees_" + liste_cas_types[i_cas_type][4:6]] = donnees
        print("donnees_" + liste_cas_types[i_cas_type][4:6])
def dessiner_graphique(donnees, revenu, affichage_en_taux):
    donnees_graph = copy.deepcopy(donnees)

    # montants (False) ou taux (True) :
    if affichage_en_taux:
        for col in donnees_graph.columns:
            if col != ("pss"):
                if col != (revenu):
                    donnees_graph[col] = donnees_graph[col] / donnees_graph[revenu]
        # globals()["donnees_taux"] = donnees_graph

    # graph
    # colonnes hors de la boucle add.trace

    col_graph_loop = donnees_graph.columns.difference(
        [
            revenu,
            "pss",
            "total_cotis_salarie",
            "total_cotis_employeur",
            "total_cotis",
        ],
        sort=False,
    )

    fig = go.Figure(
        layout=go.Layout(
            template="plotly_white",
        )
    )

    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis,
            line=dict(color="black", dash="dashdot"),
            name="total_cotis",
        )
    )
    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis_salarie,
            line=dict(color="blue", dash="dashdot"),
            name="total_cotis_salarie",
        )
    )
    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis_employeur,
            line=dict(color="red", dash="dashdot"),
            name="total_cotis_employeur",
        )
    )

    # colonne dans la boucle add.trace
    print(col_graph_loop)
    for col in col_graph_loop:
        # print(col)
        fig.add_trace(
            go.Scatter(
                x=donnees_graph.pss, y=donnees_graph[col], mode="lines", name=col
            )
        )
    fig.update_layout(
        showlegend=True,
        title={
            "text": "Cotisations (mensuelles)",
            "y": 0.9,  # new
            "x": 0.5,
            "xanchor": "center",
            "yanchor": "top",  # new
        },
        xaxis_title="PSS",
    )

    fig.show()
def comparer_donnees(donnees_A, donnees_B, revenu, affichage_en_taux):
    donnees_A_graph = copy.deepcopy(donnees_A)
    donnees_B_graph = copy.deepcopy(donnees_B)

    # montants (False) ou taux (True) :
    if affichage_en_taux:
        for col in donnees_A_graph.columns:
            if col != ("pss"):
                if col != (revenu):
                    donnees_A_graph[col] = (
                        donnees_A_graph[col] / donnees_A_graph[revenu]
                    )
        for col in donnees_B_graph.columns:
            if col != ("pss"):
                if col != (revenu):
                    donnees_B_graph[col] = (
                        donnees_B_graph[col] / donnees_B_graph[revenu]
                    )
        # globals()["donnees_taux"] = donnees_graph

    # soustraire donnees A et donnees B
    donnees_C = donnees_B_graph.subtract(donnees_A_graph, fill_value=0)

    donnees_graph = copy.deepcopy(donnees_C)

    donnees_graph[revenu] = donnees_graph[revenu]
    donnees_graph["pss"] = donnees_A_graph["pss"]

    # supprimer les colonnes avec uniquement zéros
    donnees_graph = donnees_graph.loc[:, (donnees_graph**2).sum() != 0]

    # graph
    # colonnes hors de la boucle add.trace
    col_graph_loop = donnees_graph.columns.difference(
        [
            revenu,
            "pss",
            "total_cotis_salarie",
            "total_cotis_employeur",
            "total_cotis",
        ],
        sort=False,
    )

    # creer colonnes totaux zero si inexistantes
    if "total_cotis" not in donnees_graph.columns:
        donnees_graph["total_cotis"] = 0
    if "total_cotis_salarie" not in donnees_graph.columns:
        donnees_graph["total_cotis_salarie"] = 0
    if "total_cotis_employeur" not in donnees_graph.columns:
        donnees_graph["total_cotis_employeur"] = 0

    fig = go.Figure(
        layout=go.Layout(
            template="plotly_white",
        )
    )

    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis,
            line=dict(color="black", dash="dashdot"),
            name="total_cotis",
        )
    )
    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis_salarie,
            line=dict(color="blue", dash="dashdot"),
            name="total_cotis_salarie",
        )
    )
    fig.add_trace(
        go.Scatter(
            x=donnees_graph.pss,
            y=donnees_graph.total_cotis_employeur,
            line=dict(color="red", dash="dashdot"),
            name="total_cotis_employeur",
        )
    )

    # colonne dans la boucle add.trace
    print(col_graph_loop)
    for col in col_graph_loop:
        # print(col)
        fig.add_trace(
            go.Scatter(
                x=donnees_graph.pss, y=donnees_graph[col], mode="lines", name=col
            )
        )
    fig.update_layout(
        showlegend=True,
        title={
            "text": "Cotisations (mensuelles)",
            "y": 0.9,  # new
            "x": 0.5,
            "xanchor": "center",
            "yanchor": "top",  # new
        },
        xaxis_title="PSS",
    )

    # enregistrer donnees
    globals()["donnees_A"] = donnees_A
    globals()["donnees_B"] = donnees_B
    globals()["donnees_graph"] = donnees_graph

    fig.show()
def exporter(donnees):
    # créer le nom du fichier avec date et heure
    exportfile_name = datetime.today().strftime("%Y-%m-%d %H:%M:%S")
    exportfile_name = exportfile_name.replace(" ", "-")
    exportfile_name = exportfile_name.replace(":", "-")
    exportfile_name = exportfile_name + "-output"
    exportfile_name = exportfile_name + ".xlsx"
    exportfile_name = "output" + "/" + exportfile_name
    # print(exportfile_name)

    # exporter
    donnees.to_excel(exportfile_name)

CALCULS

# calculer les cas-type (donnees)


calculer_cotisations(
    liste_cas_types=liste_cas_types_prive,
    liste_cotisations=liste_cotisations,
    revenu="salaire_de_base",
)


calculer_cotisations(
    liste_cas_types=liste_cas_types_public,
    liste_cotisations=liste_cotisations,
    revenu="traitement_indiciaire_brut",
)

# GRAPHIQUES

dessiner_graphique(
    donnees=donnees_03, revenu="traitement_indiciaire_brut", affichage_en_taux=True
)
comparer_donnees(
    donnees_A=donnees_03,
    donnees_B=donnees_05,
    revenu="traitement_indiciaire_brut",
    affichage_en_taux=True,
)
Index(['pension_employeur', 'ati_atiacl', 'mmid_employeur'], dtype='object')

EXPORTER

exporter(donnees_C)

BROUILLONS

# arbre de parametres
# simulation.tax_benefit_system.parameters.children.keys

# for k in simulation.tax_benefit_system.parameters.cotsoc.cotisations_salarie.children.keys():
#   print(k)
# retrouver les parametres
# simulation.tax_benefit_system.parameters.chomage.allocations_assurance_chomage.afd