Skip to content
Snippets Groups Projects
project.py 40 KiB
Newer Older
# Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
Juliana's avatar
Juliana committed
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from datetime import datetime, timedelta

Rémi - Le Filament's avatar
Rémi - Le Filament committed
from odoo import api, fields, models
from odoo.exceptions import ValidationError
Rémi - Le Filament's avatar
Rémi - Le Filament committed
from odoo.tools.misc import xlwt
HEADER_MEMBER = [
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    "Nom",
    "Prénom",
    "Fonction",
    "Structure",
    "Commune",
    "Mobile",
    "Fixe",
    "Email",
]
Juliana's avatar
Juliana committed

class Project(models.Model):
    _inherit = "project.project"

    @api.model
    def _default_explication_financement(self):
        if self.env.user.company_id.explication_financement:
            return self.env.user.company_id.explication_financement

Juliana's avatar
Juliana committed
    @api.model
    def _default_modalites_intervention(self):
        if self.env.user.company_id.modalites_intervention:
            return self.env.user.company_id.modalites_intervention

    @api.model
    def _default_modalites_facturation(self):
        if self.env.user.company_id.modalites_facturation:
            return self.env.user.company_id.modalites_facturation

    @api.model
    def _default_modalites_reponse(self):
        if self.env.user.company_id.modalites_reponse:
            return self.env.user.company_id.modalites_reponse

    @api.model
    def _default_modalites_modif_marche(self):
        if self.env.user.company_id.modalites_modif_marche:
            return self.env.user.company_id.modalites_modif_marche

Rémi - Le Filament's avatar
Rémi - Le Filament committed
    privacy_visibility = fields.Selection(
        [
            ("followers", "On invitation only"),
            ("employees", "Visible by all employees"),
            ("portal", "Visible by following customers"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Confidentialité",
        required=True,
        default="employees",
    )
Juliana's avatar
Juliana committed
    # Champs étape "Demande" => Vue générale
    name_subtitle = fields.Char("Sous-titre")
    first_contact_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="1er contact",
        domain=[("active", "=", True), ("is_company", "=", False)],
        ondelete="restrict",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    )
    type_contact = fields.Selection(
        [
            ("adherent", "Adhérent"),
            ("no_adherent", "Non adhérent"),
            ("pdp", "Porteur de projet"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Type contact",
    )
    date_first_contact = fields.Date("Date de 1er contact", default=fields.Date.today)
Juliana's avatar
Juliana committed
    prescripteur_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Prescripteur",
        domain=[("active", "=", True), ("is_company", "=", False)],
        ondelete="restrict",
Juliana's avatar
Juliana committed
    porteurs_projets_ids = fields.One2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner.porteur.project", "project_id", string="Porteurs de projet"
    )
Juliana's avatar
Juliana committed
    description = fields.Text("Description")
    territoire_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Territoire",
Juliana's avatar
Juliana committed
        domain=[
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("active", "=", True),
            ("is_company", "=", True),
            "|",
            ("type_structure_id.name", "=", "ComCom"),
            ("type_structure_id.name", "=", "PETR/PNR"),
        ],
        ondelete="restrict",
    departement_ids = fields.Many2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        comodel_name="res.partner",
        relation="res_partner_departement_rel",
        column1="partner_id",
        column2="departement_id",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("active", "=", True),
            ("is_company", "=", True),
            ("type_structure_id.name", "=", "Département"),
        ],
        string="Départements",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="territoire_id.departement_ids",
    )
    region_ids = fields.Many2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        comodel_name="res.partner",
        relation="res_partner_region_rel",
        column1="partner_id",
        column2="region_id",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("active", "=", True),
            ("is_company", "=", True),
            ("type_structure_id.name", "=", "Région"),
        ],
        string="Régions",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="territoire_id.region_ids",
    )
    petr_ids = fields.Many2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        comodel_name="res.partner",
        relation="res_partner_petr_rel",
        column1="partner_id",
        column2="petr_id",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("active", "=", True),
            ("is_company", "=", True),
            ("type_structure_id.name", "=", "PETR/PNR"),
        ],
        string="PETR/PNR",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="territoire_id.petr_ids",
    )
    departement = fields.Selection(
        [
            ("12", "12"),
            ("34", "34"),
            ("46", "46"),
            ("48", "48"),
            ("81", "81"),
            ("82", "82"),
        ],
        string="Département du projet",
    )
    user_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.users",
        string="CFD",
        default=lambda self: self.env.user,
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        track_visibility="onchange",
    )
Juliana's avatar
Juliana committed

    # Champs étape "Instruction" => Vue générale
    od_ids = fields.Many2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        comodel_name="res.partner",
        column1="project_id",
        column2="od_id",
        relation="res_partner_od_rel",
        string="OD",
        domain=[("active", "=", True), ("is_company", "=", True)],
        ondelete="restrict",
    elu_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Elu qui présente le dossier",
        domain=[("active", "=", True), ("is_company", "=", False)],
        ondelete="restrict",
    animateur_ids = fields.Many2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        comodel_name="res.partner",
        column1="project_id",
        column2="anim_id",
        relation="res_partner_anim_rel",
        string="Animateurs",
        domain=[("active", "=", True), ("is_company", "=", False)],
        ondelete="restrict",
Juliana's avatar
Juliana committed
    type_convention_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "adefpat.type.convention",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            "|",
            ("date_end_validity", ">=", fields.Date.today()),
            ("date_end_validity", "=", False),
        ],
        string="Type de convention de financement",
    )
    date_ca = fields.Date("Date de CA")
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    date_ca_next = fields.Date("Lendemain date de CA", compute="_compute_date_ca_next")
    date_demarrage = fields.Date("Date de démarrage prévisionnel")
Juliana's avatar
Juliana committed

    # Champs étape "Instruction" => Onglet Dossier
    contexte = fields.Text("Contexte projet")
    caract_beneficiaire = fields.Text("Caractéristiques du bénéficiaire")
    historique = fields.Text("Historique & Aujourd’hui")
    besoins_beneficiaires = fields.Text("Besoins des bénéficiaires")
    objectifs_accompagnement = fields.Text("Objectifs d’accompagnement")
    competences_requises = fields.Text("Compétences du CF")
    secteurs_requis = fields.Text("Secteurs d’activités")
Juliana's avatar
Juliana committed
    modalites_intervention = fields.Text(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Modalités d'intervention", default=_default_modalites_intervention
    )
Juliana's avatar
Juliana committed
    modalites_facturation = fields.Text(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Modalités de facturation", default=_default_modalites_facturation
    )
Juliana's avatar
Juliana committed
    modalites_reponse = fields.Text(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Modalités de réponse", default=_default_modalites_reponse
    )
Juliana's avatar
Juliana committed
    modalites_modif_marche = fields.Text(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Modalités de modification du marché", default=_default_modalites_modif_marche
    )
Juliana's avatar
Juliana committed

    # Infos dossier CA
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    type_beneficiaire = fields.Char(
        "Type de bénéficiares", compute="_compute_type_beneficiaire"
    )
Juliana's avatar
Juliana committed
    objectif_projet = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("creation", "Création d'entreprise"),
            ("creation_activite", "Création nouvelle activité"),
            ("consolidation", "Consolidation"),
            ("emergence", "Émergence"),
            ("operation", "Opération territoriale pour les entreprises"),
            ("post_creation", "Post-création"),
            ("post_reprise", "Post-reprise"),
            ("projet_inter", "Projet inter-entreprise"),
            ("projet_structurant", "Projet structurant territoire"),
            ("reprise", "Reprise"),
            ("transmission", "Transmission"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Objectif projet",
    )
Juliana's avatar
Juliana committed
    secteur_crit = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("agriculture", "Agriculture"),
            ("agro_alimentaire", "Agro-alimentaire"),
            ("artisanat", "Artisanat - Commerce - Industrie"),
            ("culture", "Culture"),
            ("environnement", "Environnement"),
            ("intersectoriel", "Intersectoriel"),
            ("service", "Service"),
            ("service", "Services à la population"),
            ("tourisme", "Tourisme - Hôtellerie - Restauration"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Secteur d'activité",
    )
Juliana's avatar
Juliana committed
    taille = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        [("inf_10", "De 10 à 250"), ("sup_10", "< 10 salariés")],
        string="Taille entreprise",
    )
Juliana's avatar
Juliana committed
    objectif_formation = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("def_projet", "Définition de projet"),
            ("def_modele_eco", "Définition d'un modèle économique"),
            ("def_strat_com", "Définition d'une stratégie de développement"),
            ("diagnostic", "Diagnostic stratégique"),
            ("gestion_prod", "Gestion de production"),
            ("gestion_financ", "Gestion financière"),
            ("marketing", "Marketing  - Commercialisation - Promotion - Communication"),
            ("management", "Management - Organisation - RH"),
            ("orga_collective", "Organisation collective"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Objectif formation",
    )
Juliana's avatar
Juliana committed
    type_formation = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("individuelle", "Générale individuelle"),
            ("collective", "Générale collective"),
            ("indiv_collect", "Générale collective individualisée"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Type formation",
    )
Juliana's avatar
Juliana committed
    encadrement = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("minimis", "De minimis"),
            ("neant", "Neant"),
            ("encadrement", "Encadrement des aides à la formation"),
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Encadrement Aides",
    )
    nb_activité = fields.Integer("Nombre d’activités ou entreprises concernées")
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    nb_coll = fields.Integer(
        "Nombre de collectivités accompagnées",
        help="Nombre de collectivités représentées dans le groupe projet "
        "(par ex 2 mairies, 1 com com et 1 petr)",
    )
    nb_citoyens = fields.Integer(
        "Nombre de citoyens participant à l'accompagnement",
        help="Ensemble des participants moins les élus et les chargés de développement, "
        "les agents de collectivités",
    )
    nb_entreprises = fields.Integer(
        "Nombre d'entreprises mobilisées dans le cadre " "d'une démarche collective",
        help="Entreprises (y compris les associations avec une activité économique "
        "régulière) participants à l'accompagnement d'un collectif inter entreprises "
        "ou à un projet territorial",
    )
    nb_emplois = fields.Integer("Nombre d’emplois concernés")
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    bpi = fields.Boolean(
        "BPI", help="projet à valoriser danS le cadre de l'appel à projet BPI"
    )
    type_accompagnement = fields.Selection(
        [
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("individualise", "Individualisé"),
            ("interentreprises", "Inter-Entreprises"),
            ("territoriaux", "Territoriaux"),
        ],
        string="Type d'accompagnement",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        help="Individualisé : accompagne d'entreprise en individuel ou collectif "
        "mais qui porte sur le developpement de chaque entreprise\n"
        "Inter-Entreprises : accompagnement de plusieurs entreprises autour "
        "d'un projet collectif\n"
        "Territoriaux : accompagnement d'un groupe multi-type d'acteurs dont "
        "au moins une collectivité",
    )
    est_suite = fields.Boolean(
        "Est ce que la sollicitation d'accompagnement est "
        "issue d'un autre accompagnement précédent sur la zone Adefpat"
    )
Juliana's avatar
Juliana committed
    lieu = fields.Text("Lieu")
    periode_realisation = fields.Text("Période de réalisation")
Juliana's avatar
Juliana committed
    contenu_formation = fields.Text("Contenu des séances")
    methode_savoir = fields.Text("Méthode et savoirs transmis")
    travaux_intersessions = fields.Text("Travaux intersessions")

    # Info Budget
    nb_jours_adefpat = fields.Float("Nombre de jours CFD")
    cout_jour_adefpat = fields.Float("Coût jour CFD")
    nb_jour_theorique_tot = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre de jours théoriques total", compute="_compute_nb_jour_theorique_tot"
    )
Juliana's avatar
Juliana committed
    nb_jour_pratique_tot = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre de jours pratiques total", compute="_compute_nb_jour_pratique_tot"
    )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre de jours plannifiés", compute="_compute_nb_jour_plann"
    )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre de jours restants", compute="_compute_nb_jour_rest"
    )
Juliana's avatar
Juliana committed
    nb_jour_tot = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre de jours total", compute="_compute_nb_jour_tot", store=True
    )
Juliana's avatar
Juliana committed
    nb_heure_tot = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Nombre d'heures' total", compute="_compute_nb_jour_tot", store=True
    )
Juliana's avatar
Juliana committed
    total_cout_adefpat = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Total coûts CFD", compute="_compute_total_cout_adefpat"
    )
Juliana's avatar
Juliana committed
    financement_adefpat = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Financement Adefpat", compute="_compute_financement_adefpat"
    )
    financement_ids = fields.One2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "adefpat.project.financement", "project_id", string="Financements"
    )
    total_financement = fields.Float(
        "Total autres", compute="_compute_total_financment"
    )
    cout_ids = fields.One2many("adefpat.project.cout", "project_id", string="Coûts")
    total_cout = fields.Float("Total coûts", compute="_compute_total_cout")
    honoraire_intervenant = fields.Float("Honoraires d'intervenants")
Juliana's avatar
Juliana committed

Juliana's avatar
Juliana committed
    total_budget_cout = fields.Float(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "Total budget coûts", compute="_compute_total_budget_cout"
    )
    total_budget_financement = fields.Float(
        "Total budget financements", compute="_compute_total_budget_financement"
    )
    explication_financement = fields.Text(
        "Explication financement porteur de projet",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=_default_explication_financement,
    )
Juliana's avatar
Juliana committed
    # Champs étape "Instruction" => Onglet Consultation
Juliana's avatar
Juliana committed
    consulant_ids = fields.One2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner.consultants.project", "project_id", string="Consultants"
    )
    date_selection = fields.Date("Date de sélection")
    date_notification = fields.Date("Date de notification")
    date_cdc = fields.Date("Date d'envoi du CDC")
Juliana's avatar
Juliana committed
    # Champs étape "Instruction" => Onglet GAP
    elu_referent_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Élu référent",
        domain=[("active", "=", True), ("is_company", "=", False)],
        ondelete="restrict",
    membre_ids = fields.One2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner.membres.project", "project_id", string="Membres"
    )
    modalite_gap = fields.Text("Modalités GAP")
    reunion_ids = fields.One2many(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "adefpat.reunion.gap", "project_id", string="Réunions"
    )
Juliana's avatar
Juliana committed

    # Champs étape "Prêt pour CA" => Onglet Général
    num_dossier = fields.Char("Numéro de dossier")

    # Champs Résultat
    closing_date = fields.Date(
        string="Date de clôture",
        help="Date de la dernière séance facturée",
    )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    on_hold = fields.Boolean(
        "Accompagement suspendus ou terminé avec l'abandon du projet"
    )
    number_gap_members = fields.Float(
        "Nombre moyen de personnes présentes GAP",
        compute="_compute_number_gap_members",
        store=True,
    )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    number_proj_att = fields.Integer(
        "Nombre de projets accompagnés dont l'objectif "
        "principal est le renforcement de l'attractivité du territoire"
    )
    number_proj_inn_idea = fields.Integer(
        "Nombre de projets aboutis considérés comme " "innovant dans leurs idées",
        help="1 - L’idée n’a jamais été développé\n"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "2 - Un projet qui sort d’un cadre normé et apporte une ou plusieurs "
        "dimensions sur les idées qui lui donne un caractère innovant\n"
        "3 - L’idée peut répondre à un besoin sur “des signaux faibles",
    )
    number_proj_inn_terr = fields.Integer(
        "Nombre de projets aboutis considérés comme "
        "innovants dans leur existence sur le territoire",
        help="1 - Le projet existe mais pas sur le territoire\n"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "2 - Le projet n’existe pas, nouveauté",
    )
    number_proj_inn_adap = fields.Integer(
        "Nombre de projets aboutis considérés comme "
        "innovants dans leur méthode d'adaptation au milieu rural",
        help="1 – Création d’un projet en collectif  et mutualiser par des entreprises "
        "(coopérer, créer pour une stratégie commune au service de tous)\n"
        "2 – L’adaptation de services urbains au milieu rural : développer le "
        "public / privé, invention de concept de modulation pour créer et pérenniser"
        "des services\n"
        "3 – L’adaptation des démarches des grandes entreprises au profit de"
        "l’entreprenariat local (au profit d’une compétitivité, l’attractivité"
        "de l’activité et de l’emploi (RSE, la dynamique managériale et"
        "organisationnelle en TPE/PME)",
    )
    number_proj_dev = fields.Integer(
        "Nombre de projet qui  ont  eu un changement d’échelle",
        help="1 - Diversification : créer une nouvelle activité pour enrichir\n"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "2 - Duplication : répliquer son modèle sur d’autres territoires\n"
        "3 - Fertilisation : à plus grande échelle\n"
        "4 - Coopération : se rapprocher d’autres structures pour faire mieux et plus\n"
        "5 - Fusion : regrouper son patrimoine avec une autre structure",
    )
    number_proj_ind_coll = fields.Integer(
        "Nombre de projet qui  sont  passés d’un projet"
        "individuel à un projet collectif",
        help="1 - Mise en lien avec d’autres porteurs projets ayant des problématiques"
        "similaires",
    )
    is_service_design = fields.Boolean(
        "Utilisation d'éléments de méthode de design de service"
    )
    is_social_impact = fields.Boolean("Intégration de notions d'Impact Social")
    synthesis_website = fields.Char("Phrase de synthèse site Internet")
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    number_comp_idea_projet = fields.Integer(
        "Nombre d'entreprises accompagnées pour passer de l'idée au projet"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    )
    number_comp_creation = fields.Integer(
        "Nombre d'entreprise en situation de création ou post création"
    number_comp_created = fields.Integer("Nombre d'entreprises créées (AI)")
    number_comp_consolidated = fields.Integer("Nombre d'entreprises consolidées")
    number_emp_created = fields.Integer("Nombre d'emplois créés")
    number_emp_consolidated = fields.Integer("Nombre d'emplois consolidés")
    number_ac_created = fields.Integer("Nombre d'actions collectives créées")
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    number_emp_created_coll = fields.Integer(
        "Nombre d'emplois crees sur le projet collectif"
    )
    number_emp_consolidated_coll = fields.Integer(
        "Nombre d'emploi consolidés par l'action collective"
    )
    number_comp_created_coll = fields.Integer(
        "Nombre d'entreprises concernées par la création"
        "d'une nouvelle activité collective"
    )
    number_struct_proj = fields.Integer(
        "Nombre de projets structurants définis"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    number_mean_people_inv = fields.Integer(
        "Nombre moyen de personnes sollicitées hors du"
        "groupe de travail (enquête, réunion publique)"
    )
    number_comp_created_at = fields.Integer("Nombre d'entreprises créées (AT)")
    number_comp_terr = fields.Integer("Nombre d'entreprises accompagnées (TERR)")
    number_day_period = fields.Float(
        "Nb jours sur période", compute="_compute_number_day_period", default=0.0)
    number_hour_period = fields.Float(
        "Nb heures sur période", compute="_compute_number_day_period", default=0.0)
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("date_ca")
    @api.multi
    def _compute_date_ca_next(self):
        for project in self:
            if project.date_ca:
                project.date_ca_next = project.date_ca + timedelta(days=1)

Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("financement_ids", "financement_ids.montant")
    @api.multi
    def _compute_total_financment(self):
        for project in self:
Juliana's avatar
Juliana committed
            total_financement = 0.0
            for financement in project.financement_ids:
Juliana's avatar
Juliana committed
                total_financement += financement.montant
            project.total_financement = total_financement
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("cout_ids", "cout_ids.montant")
    @api.multi
    def _compute_total_cout(self):
        for project in self:
Juliana's avatar
Juliana committed
            total_cout = 0.0
            for cout in project.cout_ids:
Juliana's avatar
Juliana committed
                total_cout += cout.montant
            project.total_cout = total_cout
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("cout_ids", "cout_ids.nb_jour_theorique")
    @api.multi
    def _compute_nb_jour_theorique_tot(self):
        for project in self:
            total_jour = 0.0
            for cout in project.cout_ids:
                total_jour += cout.nb_jour_theorique
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.nb_jour_theorique_tot = total_jour
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("cout_ids", "cout_ids.nb_jour_pratiques")
Juliana's avatar
Juliana committed
    @api.multi
    def _compute_nb_jour_pratique_tot(self):
        for project in self:
            total_jour = 0.0
            for cout in project.cout_ids:
                total_jour += cout.nb_jour_pratiques
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.nb_jour_pratique_tot = total_jour
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("task_ids", "task_ids.duree_hr")
    @api.multi
    def _compute_nb_jour_plann(self):
        for project in self:
            total_jour = 0.0
            for task in project.task_ids:
                total_jour += task.duree_hr
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.nb_jour_plann = total_jour
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("nb_jour_plann", "nb_jour_theorique_tot")
    @api.multi
    def _compute_nb_jour_rest(self):
        for project in self:
            project.nb_jour_rest = project.nb_jour_theorique_tot - project.nb_jour_plann

Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("cout_ids", "cout_ids.nb_jour_theorique", "cout_ids.nb_jour_pratiques")
Juliana's avatar
Juliana committed
    @api.multi
    def _compute_nb_jour_tot(self):
        for project in self:
            total_jour = 0.0
            for cout in project.cout_ids:
Juliana's avatar
Juliana committed
                total_jour += cout.nb_jour_theorique + cout.nb_jour_pratiques
Juliana's avatar
Juliana committed
            project.nb_jour_tot = total_jour
Juliana's avatar
Juliana committed
            project.nb_heure_tot = total_jour * 7
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("nb_jours_adefpat", "cout_jour_adefpat")
    @api.multi
    def _compute_total_cout_adefpat(self):
        for project in self:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.total_cout_adefpat = (
                project.nb_jours_adefpat * project.cout_jour_adefpat
            )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("total_cout_adefpat", "total_cout")
    @api.multi
    def _compute_total_budget_cout(self):
        for project in self:
            project.total_budget_cout = project.total_cout_adefpat + project.total_cout

Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("total_budget_cout", "total_financement")
    @api.multi
    def _compute_financement_adefpat(self):
        for project in self:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.financement_adefpat = (
                project.total_budget_cout - project.total_financement
            )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("financement_adefpat", "total_financement")
    @api.multi
    def _compute_total_budget_financement(self):
        for project in self:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.total_budget_financement = (
                project.financement_adefpat + project.total_financement
            )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("porteurs_projets_ids", "porteurs_projets_ids.statut")
    @api.multi
    def _compute_type_beneficiaire(self):
        for project in self:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.type_beneficiaire = ", ".join(
                project.porteurs_projets_ids.mapped("statut.name")
            )
    @api.depends("reunion_ids", "reunion_ids.number_participants")
    @api.multi
    def _compute_number_gap_members(self):
        for project in self:
            project.number_gap_members = sum(
                project.reunion_ids.mapped("number_participants")) / len(
                project.reunion_ids
            ) if project.reunion_ids else 0
    @api.multi
    def _compute_number_day_period(self):
        """
        fonction qui calcule le nombre de jours et heures par séance
        pour des valeurs passées dans le contexte
        """
        period_start = fields.Date.to_date(self.env.context.get("period_start"))
        period_end = fields.Date.to_date(self.env.context.get("period_end"))
        for project in self:
            days = project.task_ids.filtered(
                lambda t: t.date_deadline and t.date_deadline >= period_start
                and t.date_deadline <= period_end).mapped("duree_hr")
            project.number_day_period = sum(days)
            project.number_hour_period = sum(days) * 7

    @api.multi
    def validate_ca(self):
        for project in self:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            project.num_dossier = (
                project.departement
                + "/"
                + datetime.strftime(datetime.today(), "%y")
                + "/"
                + self.env["ir.sequence"].next_by_code("increment_num_dossier")
            )

    def get_workbook(self, filename_, project_id, partner_type):
        project = self.env["project.project"].search([("id", "=", project_id)])
        workbook = xlwt.Workbook()
        worksheet = workbook.add_sheet(filename_)

Rémi - Le Filament's avatar
Rémi - Le Filament committed
        if partner_type == "gap":
Juliana's avatar
Juliana committed
            gap_ids = project.membre_ids
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        if partner_type == "benef":
Juliana's avatar
Juliana committed
            gap_ids = project.porteurs_projets_ids

        header_file = HEADER_MEMBER
        for i, fieldname in enumerate(header_file):
            worksheet.write(0, i, fieldname)
            worksheet.col(i).width = 8000  # around 220 pixels

Rémi - Le Filament's avatar
Rémi - Le Filament committed
        base_style = xlwt.easyxf("align: wrap yes")
        cell_style = base_style

        row_index = 1

        for gap_id in gap_ids:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            worksheet.write(row_index, 0, str(gap_id.lastname), cell_style)
            worksheet.write(row_index, 1, str(gap_id.firstname), cell_style)
            if partner_type == "gap":
Juliana's avatar
Juliana committed
                if gap_id.partner_id.function:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(
                        row_index, 2, str(gap_id.partner_id.function), cell_style
                    )
Juliana's avatar
Juliana committed
                else:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(row_index, 2, "None", cell_style)
Juliana's avatar
Juliana committed
                if gap_id.partner_id.parent_id:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(
                        row_index, 3, str(gap_id.partner_id.parent_id.name), cell_style
                    )
Juliana's avatar
Juliana committed
                else:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(row_index, 3, "None", cell_style)
            if partner_type == "benef":
Juliana's avatar
Juliana committed
                if gap_id.porteur_id.function:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(
                        row_index, 2, str(gap_id.porteur_id.function), cell_style
                    )
Juliana's avatar
Juliana committed
                else:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(row_index, 2, "None", cell_style)
Juliana's avatar
Juliana committed
                if gap_id.porteur_id.parent_id:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(
                        row_index, 3, str(gap_id.porteur_id.parent_id.name), cell_style
                    )
Juliana's avatar
Juliana committed
                else:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    worksheet.write(row_index, 3, "None", cell_style)
            worksheet.write(row_index, 4, str(gap_id.commune), cell_style)
            worksheet.write(row_index, 5, str(gap_id.mobile), cell_style)
            worksheet.write(row_index, 6, str(gap_id.fixe), cell_style)
            worksheet.write(row_index, 7, str(gap_id.email), cell_style)
            row_index = row_index + 1
        return workbook

    @api.multi
    def export_gap(self):
        for project in self:
            filename_ = project.name
            project_id = project.id
            return {
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                "type": "ir.actions.act_url",
                "url": "/web/export_gap?filename_=%s&project_id=%s&partner_type=%s"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                % (filename_, project_id, "gap"),
                "target": "new",
Juliana's avatar
Juliana committed
            }

    @api.multi
    def export_benef(self):
        for project in self:
            filename_ = project.name
            project_id = project.id
            return {
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                "type": "ir.actions.act_url",
                "url": "/web/export_gap?filename_=%s&project_id=%s&partner_type=%s"
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                % (filename_, project_id, "benef"),
                "target": "new",
    @api.multi
    def write(self, values):
        res = super(Project, self).write(values)
        for project in self:
            # Mise à jour des participant sur les séances si ajout
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            if values.get("porteurs_projets_ids"):
                participant_ids = []
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                for porteur in values.get("porteurs_projets_ids"):
                    if porteur[2]:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                        if porteur[2].get("eligible") and porteur[2].get("porteur_id"):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                                "porteur_id": porteur[2]["porteur_id"],
                                "eligible": porteur[2]["eligible"],
                            }
                            participant_ids.append((0, 0, vals))
                for task in project.task_ids:
Rémi - Le Filament's avatar
Rémi - Le Filament committed
                    task.update({"participant_ids": participant_ids})
Juliana's avatar
Juliana committed

class AdefpatTypeConvention(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "adefpat.type.convention"
    _description = "Liste type de convention"
Juliana's avatar
Juliana committed

    name = fields.Char(
        string="Convention",
        required=True,
    )
    date_end_validity = fields.Date("Date de fin de validité")
    is_fd = fields.Boolean("FD")
Juliana's avatar
Juliana committed


class AdefpatReunionGAP(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "adefpat.reunion.gap"
    _description = "Réunions GAP"
    _rec_name = "date"
Juliana's avatar
Juliana committed

    @api.model
    def _default_participant_ids(self):
        if "default_project_id" in self.env.context:
            project_id = self.env["project.project"].browse(
                self.env.context["default_project_id"]
            )
            if project_id.exists().membre_ids:
                participant_ids = project_id.membre_ids.mapped(lambda p: (0, 0, {
                    "member_id": p.id,
                    "present": False
                }))
                self.update({"participant_ids": participant_ids})
                return participant_ids
    date = fields.Date(
        string="Date du GAP",
        required=True,
    )
Juliana's avatar
Juliana committed
    project_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "project.project",
        string="Projet",
        required=True,
        ondelete="cascade",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=lambda self: self.env.context.get("default_project_id"),
    )
    participant_ids = fields.One2many(
        comodel_name="res.partner.reunion.gap",
        inverse_name="gap_id",
        string="Participants",
        default=_default_participant_ids
    )
    number_participants = fields.Integer(
        string="Moyenne de participants",
        compute="_compute_number_participants",
        group_operator="avg",
        store=True
    @api.depends("participant_ids", "participant_ids.present")
    @api.multi
    def _compute_number_participants(self):
        for gap in self:
            gap.number_participants = len(gap.participant_ids.filtered("present"))
Juliana's avatar
Juliana committed


class AdefpatMembresProjets(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "res.partner.membres.project"
    _description = "Membres"
Juliana's avatar
Juliana committed

    partner_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Membre",
        domain=[("active", "=", True), ("is_company", "=", False)],
        required=True,
        ondelete="restrict",
    name = fields.Char(related="partner_id.name", store=False)
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    lastname = fields.Char(related="partner_id.lastname", string="Nom", store=False)
Juliana's avatar
Juliana committed
    firstname = fields.Char(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="partner_id.firstname", string="Prénom", store=False
    )
    commune = fields.Char(related="partner_id.city", string="Commune", store=False)
    mobile = fields.Char(related="partner_id.mobile", string="Mobile", store=False)
    fixe = fields.Char(related="partner_id.phone", string="Fixe", store=False)
    email = fields.Char(related="partner_id.email", string="Email", store=False)
    project_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "project.project",
        string="Projet",
        required=True,
        ondelete="cascade",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=lambda self: self.env.context.get("default_project_id"),
    )
Juliana's avatar
Juliana committed


class AdefpatConsultantsProjets(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "res.partner.consultants.project"
    _description = "Consultants"
    _rec_name = "name"
Juliana's avatar
Juliana committed

    partner_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Consultant",
Juliana's avatar
Juliana committed
        domain=[
Rémi - Le Filament's avatar
Rémi - Le Filament committed
            ("active", "=", True),
            ("is_company", "=", False),
            ("is_consultant_form", "=", True),
            "|",
            ("reference", "=", "reference"),
            ("reference", "=", "prereference"),
        ],
        required=True,
        ondelete="restrict",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    )
    name = fields.Char(related="partner_id.name")
    lastname = fields.Char(related="partner_id.lastname", string="Nom", store=False)
Juliana's avatar
Juliana committed
    firstname = fields.Char(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="partner_id.firstname", string="Prénom", store=False
    )
    mobile = fields.Char(related="partner_id.mobile", string="Mobile", store=False)
    email = fields.Char(related="partner_id.email", string="Email", store=False)
    reference = fields.Selection(
        [
            ("reference", "Référencé"),
            ("prereference", "Pré-Référencé"),
            ("dereference", "Dé-Référencé"),
        ],
        related="partner_id.reference",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        store=False,
    )
    cout_journée = fields.Float("Coût journée")
    is_selected = fields.Boolean("Est sélectionné")
Juliana's avatar
Juliana committed
    project_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "project.project",
        string="Projet",
        required=True,
        ondelete="cascade",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=lambda self: self.env.context.get("default_project_id"),
    )
Juliana's avatar
Juliana committed


class AdefpatPorteursProjets(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "res.partner.porteur.project"
    _description = "Porteurs de projets"
    _rec_name = "name"
Juliana's avatar
Juliana committed

    porteur_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "res.partner",
        string="Porteur de projet",
        domain=[("is_company", "=", False)],
        required=True,
        ondelete="restrict",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    name = fields.Char(related="porteur_id.name")
    lastname = fields.Char(related="porteur_id.lastname", string="Nom", store=False)
Juliana's avatar
Juliana committed
    firstname = fields.Char(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="porteur_id.firstname", string="Prénom", store=False
    )
    sexe = fields.Selection(related="porteur_id.sexe", string="Sexe", store=False)
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    commune = fields.Char(compute="_compute_commune", string="Commune", store=False)
    est_dans_comcom = fields.Boolean(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        string="Commune dans ComCom du lieu de formation",
        help="En cas de lieu tournant, si un des lieux de formation est sur la com com "
             "du PP cocher la case",
    )
    date_naissance = fields.Date(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="porteur_id.date_naissance", string="Date de naissance"
    )
    mobile = fields.Char(related="porteur_id.mobile", string="Mobile", store=False)
    fixe = fields.Char(related="porteur_id.phone", string="Fixe", store=False)
    email = fields.Char(related="porteur_id.email", string="Email", store=False)
    statut = fields.Many2one("adefpat.project.statut", string="Statut")
    eligible = fields.Boolean(string="Eligible", default=True)
    is_benef_form = fields.Boolean(string="Fiches bénéficiaires")
    h_pratiques = fields.Boolean("H pratiques")
    h_theoriques = fields.Boolean("H théoriques")
Juliana's avatar
Juliana committed
    task_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "project.task",
        string="Séance",
        ondelete="cascade",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=lambda self: self.env.context.get("default_task_id"),
    )
    project_id = fields.Many2one(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        "project.project",
        string="Projet",
        ondelete="cascade",
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        default=lambda self: self.env.context.get("default_project_id"),
    )
    project_num = fields.Char(
        related="project_id.num_dossier", string="Numéro du dossier"
    )
    project_secteur = fields.Selection(
Rémi - Le Filament's avatar
Rémi - Le Filament committed
        related="project_id.secteur_crit", string="Secteur d'activité du dossier"
    )
    departement = fields.Selection(
        related="project_id.departement", string="Département"
    number_hour_period = fields.Float(
        "Nb heures sur période", compute="_compute_hour_period", default=0.0)
    # ------------------------------------------------------
    # Constrains
    # ------------------------------------------------------
    @api.constrains("task_id", "project_id")
    def _check_task_or_project(self):
        for pp in self:
            if not pp.task_id and not pp.project_id:
                raise ValidationError(
                    "Un porteur de projet doit être associé à une tâche ou un projet."
                )
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    @api.depends("porteur_id")
    def _compute_commune(self):
        for r in self:
Juliana's avatar
Juliana committed
            if r.porteur_id.city:
                r.commune = r.porteur_id.city.capitalize()
    @api.multi
    def _compute_hour_period(self):
        """
        fonction qui calcule le nombre d'heures par bénéficiaire
        pour des valeurs passées dans le contexte
        """
        period_start = fields.Date.from_string(self.env.context.get("period_start"))
        period_end = fields.Date.from_string(self.env.context.get("period_end"))
        for line in self:
            if line.project_id:
                task_ids = line.project_id.task_ids.filtered(
                    lambda t: t.date_deadline and t.date_deadline >= period_start
                    and t.date_deadline <= period_end)
                days = []
                for task in task_ids:
                    participant_ids = task.participant_ids.filtered(
                        lambda p: p.h_theoriques)
                    if line.porteur_id in participant_ids.mapped("porteur_id"):
                        days.append(task.duree_hr * 7)
                line.number_hour_period = sum(days)
class AdefpatPresentsGap(models.Model):
    _name = "res.partner.reunion.gap"
    _description = "Présents GAP"

    member_id = fields.Many2one(
        "res.partner.membres.project",
        string="Membre",
        required=True,
        ondelete="restrict",
    )
    gap_id = fields.Many2one(
        "adefpat.reunion.gap",
        string="Séance GAP",
        default=lambda self: self.env.context.get("default_gap_id"),
        ondelete="cascade",
    )
    present = fields.Boolean("Présent")


class AdefpatStatut(models.Model):
Rémi - Le Filament's avatar
Rémi - Le Filament committed
    _name = "adefpat.project.statut"
    _description = "Statut"