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

from datetime import datetime, timedelta
from odoo import models, fields, api
from odoo.tools.misc import xlwt
Juliana's avatar
Juliana committed

import csv
import base64

HEADER_MEMBER = [
    'Nom',
    'Prénom',
    '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

    privacy_visibility = fields.Selection([
            ('followers', 'On invitation only'),
            ('employees', 'Visible by all employees'),
            ('portal', 'Visible by following customers'),
        ],
        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(
        'res.partner',
        string='1er contact',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', False)],
        on_delete='restrict')
    type_contact = fields.Selection([
        ('adherent', 'Adhérent'),
        ('no_adherent', 'Non adhérent'),
        ('pdp', 'Porteur de projet'),
        ],
Juliana's avatar
Juliana 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(
        'res.partner',
        string='Prescripteur',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', False)],
        on_delete='restrict')
Juliana's avatar
Juliana committed
    porteurs_projets_ids = fields.One2many(
        'res.partner.porteur.project',
        'project_id',
Juliana's avatar
Juliana committed
        string="Porteurs de projet")
    description = fields.Text("Description")
    territoire_id = fields.Many2one(
        'res.partner',
        string='Territoire',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', True),
            '|',
            ('type_structure_id.name', '=', 'ComCom'),
            ('type_structure_id.name', '=', 'PETR/PNR')],
        on_delete='restrict')
    departement_ids = fields.Many2many(
        comodel_name='res.partner',
        relation='res_partner_departement_rel',
        column1='partner_id',
        column2='departement_id',
        domain=[
            ('active', '=', True),
            ('is_company', '=', True),
            ('type_structure_id.name', '=', 'Département')],
        string="Départements",
        related='territoire_id.departement_ids')
    region_ids = fields.Many2many(
        comodel_name='res.partner',
        relation='res_partner_region_rel',
        column1='partner_id',
        column2='region_id',
        domain=[
            ('active', '=', True),
            ('is_company', '=', True),
            ('type_structure_id.name', '=', 'Région')],
        string="Régions",
        related='territoire_id.region_ids')
    petr_ids = fields.Many2many(
        comodel_name='res.partner',
        relation='res_partner_petr_rel',
        column1='partner_id',
        column2='petr_id',
        domain=[
            ('active', '=', True),
            ('is_company', '=', True),
            ('type_structure_id.name', '=', 'PETR/PNR')],
        string="PETR/PNR",
        related='territoire_id.petr_ids')
Juliana's avatar
Juliana committed
    departement = fields.Selection([
        ('12', '12'),
        ('34', '34'),
        ('46', '46'),
        ('48', '48'),
        ('81', '81'),
        ('82', '82')
    ], string="Département du projet")
    user_id = fields.Many2one(
        string='CFD', 
        default=lambda self: self.env.user, 
        track_visibility="onchange")
Juliana's avatar
Juliana committed

    # Champs étape "Instruction" => Vue générale
    od_ids = fields.Many2many(
        comodel_name='res.partner',
        column1='project_id',
        column2='od_id',
        relation='res_partner_od_rel',
Juliana's avatar
Juliana committed
        string='OD',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', True)],
        on_delete='restrict')
    elu_id = fields.Many2one(
Juliana's avatar
Juliana committed
        'res.partner',
        string='Elu qui présente le dossier',
        domain=[
            ('active', '=', True),
            ('is_company', '=', False)],
        on_delete='restrict')
    animateur_ids = fields.Many2many(
        comodel_name = 'res.partner',
        column1='project_id',
        column2='anim_id',
        relation='res_partner_anim_rel',
        string='Animateurs',
Juliana's avatar
Juliana committed
        domain=[
            ('active', '=', True), 
            ('is_company', '=', False)],
        on_delete='restrict')
    type_convention_id = fields.Many2one(
        'adefpat.type.convention', 
        domain=[
            '|', ('date_end_validity', '>=', fields.Date.today()),
            ('date_end_validity', '=', False)],
Juliana's avatar
Juliana committed
        string="Type de convention de financement")
    date_ca = fields.Date("Date de CA")
    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("Modalités d'intervention")
    modalites_facturation = fields.Text("Modalités de facturation")
    modalites_reponse = fields.Text("Modalités de réponse")

    # Infos dossier CA
    type_beneficiaire = fields.Char("Type de bénéficiares", compute='_compute_type_beneficiaire')
Juliana's avatar
Juliana committed
    objectif_projet = fields.Selection(
        [
            ('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'),
Juliana's avatar
Juliana committed
        string="Objectif projet")
    secteur_crit = fields.Selection(
            ('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'),
Juliana's avatar
Juliana committed
        string="Secteur d'activité")
    taille = fields.Selection(
        [
            ('inf_10', "De 10 à 250"),
            ('sup_10', "< 10 salariés")
        ],
Juliana's avatar
Juliana committed
        string="Taille entreprise")
    objectif_formation = fields.Selection(
        [
            ('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'),
Juliana's avatar
Juliana committed
        string="Objectif formation")
    type_formation = fields.Selection(
        [
            ('individuelle', 'Générale individuelle'),
            ('collective', 'Générale collective'),
            ('indiv_collect', 'Générale collective individualisée'),
        ],
Juliana's avatar
Juliana committed
        string="Type formation")
    encadrement = fields.Selection(
        [
            ('minimis', 'De minimis'),
            ('neant', 'Neant'),
            ('encadrement', 'Encadrement des aides à la formation')
        ],
Juliana's avatar
Juliana committed
        string="Encadrement Aides")
    nb_activité = fields.Integer("Nombre d’activités ou entreprises concernées")
    nb_emplois = fields.Integer("Nombre d’emplois concernés")
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(
        "Nombre de jours théoriques total", 
        compute='_compute_nb_jour_theorique_tot')
Juliana's avatar
Juliana committed
    nb_jour_tot = fields.Float(
        "Nombre de jours total",
        compute='_compute_nb_jour_tot')
    nb_heure_tot = fields.Float(
        "Nombre d'heures' total",
        compute='_compute_nb_jour_tot')
Juliana's avatar
Juliana committed
    total_cout_adefpat = fields.Float(
        "Total coûts CFD", 
        compute='_compute_total_cout_adefpat')
    financement_adefpat = fields.Float(
        "Financement Adefpat", 
        compute='_compute_financement_adefpat')
    financement_ids = fields.One2many(
        '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(
        "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",
        default=_default_explication_financement)
Juliana's avatar
Juliana committed
    # Champs étape "Instruction" => Onglet Consultation
Juliana's avatar
Juliana committed
    consulant_ids = fields.One2many(
        'res.partner.consultants.project',
        'project_id',
Juliana's avatar
Juliana committed
        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(
        'res.partner',
        string='Élu référent',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', False)],
        on_delete='restrict')
    membre_ids = fields.One2many(
        'res.partner.membres.project',
        'project_id',
Juliana's avatar
Juliana committed
        string="Membres")
    modalite_gap = fields.Text("Modalités GAP")
    reunion_ids = fields.One2many(
        '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")

    @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)

    @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

    @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
    @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
Juliana's avatar
Juliana committed
            project.nb_jour_theorique_tot = total_jour\

    @api.depends('cout_ids', 'cout_ids.nb_jour_theorique', 'cout_ids.nb_jour_pratiques')
    @api.multi
    def _compute_nb_jour_tot(self):
        for project in self:
            total_jour = 0.0
            total_heure = 0.0
            for cout in project.cout_ids:
                total_jour += cout.nb_jour_tot
                total_heure += cout.nb_heure_tot
            project.nb_jour_tot = total_jour
            project.nb_heure_tot = total_heure * 7
    @api.depends('nb_jours_adefpat', 'cout_jour_adefpat')
    @api.multi
    def _compute_total_cout_adefpat(self):
        for project in self:
            project.total_cout_adefpat = project.nb_jours_adefpat * project.cout_jour_adefpat

    @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

    @api.depends('total_budget_cout', 'total_financement')
    @api.multi
    def _compute_financement_adefpat(self):
        for project in self:
            project.financement_adefpat = project.total_budget_cout - project.total_financement

    @api.depends('financement_adefpat', 'total_financement')
    @api.multi
    def _compute_total_budget_financement(self):
        for project in self:
            project.total_budget_financement = project.financement_adefpat + project.total_financement

    @api.depends('porteurs_projets_ids',
                 'porteurs_projets_ids.statut')
    @api.multi
    def _compute_type_beneficiaire(self):
        for project in self:
            project.type_beneficiaire = ', '.join(project.porteurs_projets_ids.mapped('statut.name'))
    @api.multi
    def validate_ca(self):
        for project in self:
            project.num_dossier = project.departement + '/' + datetime.strftime(datetime.today(), '%y') + '/' + self.env['ir.sequence'].next_by_code(
    def get_workbook(self, filename_, project_id):
        project = self.env['project.project'].search([('id', '=', project_id)])
        workbook = xlwt.Workbook()
        worksheet = workbook.add_sheet(filename_)

        gap_ids = project.membre_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

        base_style = xlwt.easyxf('align: wrap yes')
        cell_style = base_style

        row_index = 1

        for gap_id in gap_ids:
            worksheet.write(row_index, 0,
                            str(gap_id.lastname), cell_style)
            worksheet.write(row_index, 1,
                            str(gap_id.firstname), cell_style)
            worksheet.write(row_index, 2,
                            str(gap_id.commune), cell_style)
            worksheet.write(row_index, 3,
                            str(gap_id.mobile), cell_style)
            worksheet.write(row_index, 4,
                            str(gap_id.fixe), cell_style)
            worksheet.write(row_index, 5,
                            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 {
                'type': 'ir.actions.act_url',
                'url':
                    '/web/export_gap?filename_=%s&project_id=%s'
                    % (filename_, project_id),
                'target': 'new',
            }
Juliana's avatar
Juliana committed

class AdefpatTypeConvention(models.Model):
    _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é")
Juliana's avatar
Juliana committed


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

    # document_ids = fields.One2many('ir.attachment', string="Documents")
    date = fields.Date(
        string="Date du GAP",
        required=True,
    )
Juliana's avatar
Juliana committed
    project_id = fields.Many2one(
        'project.project',
        string='Projet',
        default=lambda self: self.env.context.get('default_project_id'))


class AdefpatMembresProjets(models.Model):
    _name = 'res.partner.membres.project'
    _description = 'Membres'

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


class AdefpatConsultantsProjets(models.Model):
    _name = 'res.partner.consultants.project'
    _description = 'Consultants'
    _rec_name = 'name'
Juliana's avatar
Juliana committed

    partner_id = fields.Many2one(
        'res.partner',
        string='Consultant',
        domain=[
            ('active', '=', True), 
            ('is_company', '=', False),
            ('is_consultant_form', '=', True),
            '|', ('reference', '=', 'reference'),
            ('reference', '=', 'prereference')],
        required=True,
Juliana's avatar
Juliana committed
        on_delete='restrict')
    name = fields.Char(related='partner_id.name')
Juliana's avatar
Juliana committed
    lastname = fields.Char(
        related='partner_id.lastname', 
Juliana's avatar
Juliana committed
    firstname = fields.Char(
        related='partner_id.firstname', 
Juliana's avatar
Juliana committed
    mobile = fields.Char(
        related='partner_id.mobile', 
Juliana's avatar
Juliana committed
    email = fields.Char(
        related='partner_id.email', 
Juliana's avatar
Juliana committed
    reference = fields.Selection([
        ('reference', 'Référencé'),
        ('prereference', 'Pré-Référencé'),
        ('dereference', 'Dé-Référencé')],
        related='partner_id.reference',
        string="Référencement",
        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(
        'project.project',
        string='Projet',
        default=lambda self: self.env.context.get('default_project_id'))
Juliana's avatar
Juliana committed


class AdefpatPorteursProjets(models.Model):
    _name = 'res.partner.porteur.project'
    _description = 'Porteurs de projets'
    _rec_name = 'name'
Juliana's avatar
Juliana committed

    porteur_id = fields.Many2one(
Juliana's avatar
Juliana committed
        'res.partner',
        string='Porteur de projet',
        domain=[('is_company', '=', False)],
        required=True,
        on_delete='restrict'
    )
    name = fields.Char(related='porteur_id.name')
Juliana's avatar
Juliana committed
    lastname = fields.Char(
Juliana's avatar
Juliana committed
        related='porteur_id.lastname',
Juliana's avatar
Juliana committed
    firstname = fields.Char(
Juliana's avatar
Juliana committed
        related='porteur_id.firstname',
Juliana's avatar
Juliana committed
    commune = fields.Char(
        compute='_compute_commune',
Juliana's avatar
Juliana committed
    mobile = fields.Char(
Juliana's avatar
Juliana committed
        related='porteur_id.mobile',
Juliana's avatar
Juliana committed
    fixe = fields.Char(
Juliana's avatar
Juliana committed
        related='porteur_id.phone',
Juliana's avatar
Juliana committed
    email = fields.Char(
Juliana's avatar
Juliana committed
        related='porteur_id.email',
    statut = fields.Many2one(
        'adefpat.project.statut',
Juliana's avatar
Juliana committed
        string="Statut")
    eligible = fields.Boolean(
        string="Eligible")
Juliana's avatar
Juliana committed
    is_present = fields.Boolean("Est présent")
    task_id = fields.Many2one(
        'project.task',
        string='Séance',
Juliana's avatar
Juliana committed
        default=lambda self: self.env.context.get('default_task_id'))
    project_id = fields.Many2one(
        'project.project',
        string='Projet',
        default=lambda self: self.env.context.get('default_project_id'))
    @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.lower()


class AdefpatStatut(models.Model):
    _name = 'adefpat.project.statut'
    _description = 'Statut'

    name = fields.Char("Statut", required=True,)


class AdefpatFinancement(models.Model):
    _name = 'adefpat.project.financement'
    _description = 'Financements'

    partner_id = fields.Many2one(
        'res.partner',
        string='Facturation',
        domain=[
            ('active', '=', True)],
        required=True,
        on_delete='restrict'
    )
    montant = fields.Float("Montant")
    project_id = fields.Many2one(
        'project.project',
        string='Projet',
        default=lambda self: self.env.context.get('default_project_id'))


class AdefpatCout(models.Model):
    _name = 'adefpat.project.cout'
    _description = 'Coûts'

Juliana's avatar
Juliana committed
    module = fields.Char("Nom du module")
    partner_id = fields.Many2one(
        'res.partner',
        string='Consultant',
            ('active', '=', True),
            ('is_company', '=', False),
            ('is_consultant_form', '=', True)],
Juliana's avatar
Juliana committed
        on_delete='restrict',)
    nb_jour_theorique = fields.Float("Nombre de jours théoriques")
    nb_jour_pratiques = fields.Float("Nombre de jours pratiques")
    nb_jour_tot = fields.Float("Nombre de jours total", compute='_compute_nb_jour_tot', store=True)
    nb_heure_tot = fields.Float("Nombre d'heures total", compute='_compute_nb_jour_tot', store=True)
    cout_jour = fields.Float("Coût jour")
    montant = fields.Float("Montant", compute='_compute_montant', store=True)
    project_id = fields.Many2one(
        'project.project',
        string='Projet',
        default=lambda self: self.env.context.get('default_project_id'))

    @api.depends('cout_jour', 'nb_jour_theorique')
    def _compute_montant(self):
        for r in self:
            r.montant = r.cout_jour * r.nb_jour_theorique\

    @api.depends('nb_jour_pratiques', 'nb_jour_theorique')
    def _compute_nb_jour_tot(self):
        for r in self:
            r.nb_jour_tot = r.nb_jour_pratiques * r.nb_jour_theorique
            r.nb_heure_tot = r.nb_jour_tot * 7