Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • 4153dcde1a214699f5533692d064c8f794a26d07
  • 14.0 par défaut
  • 13.0
  • 12.0 protégée
4 résultats

calendar.py

Blame
  • res_partner.py 18,92 Kio
    # © 2022 Le Filament (<http://www.le-filament.com>)
    # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
    
    from pytz import timezone
    
    from odoo import _, api, fields, models
    from odoo.exceptions import ValidationError
    
    
    class ScopPartner(models.Model):
        _inherit = "res.partner"
    
        # Processus d'adhésion
        project_number = fields.Char("N° Projet")
        percent_realisation = fields.Selection(
            [
                ("0", "0"),
                ("20", "20"),
                ("40", "40"),
                ("60", "60"),
                ("80", "80"),
                ("100", "100"),
            ],
            string="Probabilité de réalisation",
        )
        date_realisation = fields.Date("Date prévue de réalisation")
        prescriber_canal_id = fields.Many2one(
            "res.partner.prescriber.canal",
            string="Canal de Prescription",
            ondelete="restrict",
        )
        project_federation = fields.Many2one(
            comodel_name="res.partner.federation",
            string="Fédération",
            ondelete="restrict",
            tracking=True,
        )
    
        date_first_rdv = fields.Date("Date du 1er rdv")
        year_project = fields.Char("Année du projet", compute="_compute_year_project")
        is_first_rdv_infocoll = fields.Boolean("Réunion d'info. collective")
        date_send_guide = fields.Date("Date d’envoi du guide de faisabilité")
        date_abort = fields.Date("Date d'abandon")
        abort_comments = fields.Text("Commentaires abandon projet")
        staff_existing = fields.Integer("Effectif connu")
        staff_planned = fields.Integer("Effectif prévu")
        ca_previsionnel = fields.Integer("CA Prévisionnel")
        adhesion_comments = fields.Text("Commentaires Adhésion")
    
        feasibility_study = fields.Boolean("Etude de faisabilité signée / validée")
        amount_feasibility_study = fields.Integer("Montant de l’étude de faisabilité")
        date_prediag = fields.Date("Date de pré-diagnostic")
        date_convention = fields.Date("Date de signature de la convention")
        amount_convention = fields.Integer("Montant de la convention")
        file_full = fields.Boolean("Dossier d’adhésion complet")
        date_transmission_cg = fields.Date("Date de transmission du dossier à la CG")
        date_bureau_validation = fields.Date("Date du bureau de validation")
    
        lm_adhesion_id = fields.Many2one(
            comodel_name="scop.liste.ministere", string="Liste Ministère adhésion"
        )
        lm_adhesion_year = fields.Integer(
            string="Année dossier adhésion", related="lm_adhesion_id.year"
        )
        invoice_adhesion_id = fields.Many2one(
            comodel_name="account.move", string="Facture d'adhésion"
        )
    
        # Dossier UE
        file_fse_open = fields.Boolean("Dossier FSE ouvert Oui/Non")
        is_id_card = fields.Boolean("Carte d'identité reçue")
        date_return_file = fields.Date("Date de retour du dossier")
        fse_full = fields.Boolean("FSE Complet")
        recipient_file_fse = fields.Many2one(
            "res.partner", string="Destinataire du dossier FSE"
        )
        project_invoicing_status_id = fields.Many2many(
            "res.partner.project.invoicing.status",
            column1="partner_id",
            column2="invoicing_status_id",
            string="Etat de facturation",
        )
        project_invoicing_status_nb = fields.Integer(
            string="Nb de statuts de facturation",
            compute="_compute_project_invoicing_status_nb",
        )
    
        # Changement de statuts
        list_logs = fields.Text("Liste des erreurs")
    
        # ------------------------------------------------------
        # Compute function
        # ------------------------------------------------------
        def _compute_project_invoicing_status_nb(self):
            for partner in self:
                # Calcul nombre de statut 1
                sta = partner.env["res.partner.project.invoicing.status"].search(
                    [("ur_id", "=", self.env.user.ur_id.id)]
                )
                partner.project_invoicing_status_nb = len(sta)
    
        def _compute_year_project(self):
            for partner in self:
                partner.year_project = None
                if partner.date_first_rdv:
                    partner.year_project = str(partner.date_first_rdv.year)
    
        # ------------------------------------------------------
        # Onchange function
        # ------------------------------------------------------
        @api.onchange("project_status")
        def _onchange_project_status(self):
            if self.project_status != "7_abandonne":
                self.date_abort = None
    
        # ------------------------------------------------------
        # Actions / Buttons
        # ------------------------------------------------------
        def scop_lm_adhesion(self):
            """
            Display liste ministere form used for adhesion
            :return: Form View LM
            """
            self.ensure_one()
            if not self.lm_adhesion_id:
                self.lm_adhesion_id = self.get_lm_adhesion()
            form_id = self.env.ref("cgscop_liste_ministere.view_liste_ministere_form")
            action = {
                "name": "Dossier d'adhésion",
                "type": "ir.actions.act_window",
                "res_model": "scop.liste.ministere",
                "view_mode": "form",
                "views": [[form_id.id, "form"]],
                "res_id": self.lm_adhesion_id.id,
                "context": {"create": False, "edit": True, "delete": False},
            }
            return action
    
        def scop_liasse_adhesion(self):
            """
            Display liasse fiscale used for adhesion :
            :return LF attached to LM adhesion or create new one type prévi
            """
            self.ensure_one()
            if not self.lm_adhesion_id:
                self.lm_adhesion_id = self.get_lm_adhesion()
            liasse_adhesion = self.get_liasse_adhesion(self.lm_adhesion_id)
            year_adhesion = self.lm_adhesion_year
            if not liasse_adhesion.year == year_adhesion:
                liasse_adhesion.update({"year": year_adhesion})
            action = self.env["ir.actions.actions"]._for_xml_id(
                "cgscop_liasse_fiscale.scop_liasse_fiscale_previsionnelle_act_window"
            )
            action.update(
                {
                    "name": "Données financières",
                    "res_id": liasse_adhesion.id,
                    "context": {"create": False, "edit": True, "delete": False},
                }
            )
            return action
    
        def scop_change_year_dossier(self):
            """
            Open wizard to change year dossier adhesion
            :return:
            """
            wizard = self.env["scop.adhesion.year.wizard"].create(
                {"lm_adhesion_id": self.lm_adhesion_id.id}
            )
            return {
                "name": "Modifier l'année du dossier",
                "type": "ir.actions.act_window",
                "view_mode": "form",
                "res_model": "scop.adhesion.year.wizard",
                "res_id": wizard.id,
                "target": "new",
            }
    
        # ------------------------------------------------------
        # Business methods
        # ------------------------------------------------------
        def get_lm_adhesion(self, year=False):
            """
            - LM renouvellement existante en année N → on rattache à cette LM
            - Pas de LM existante en année N
                - LM connue dans l’historique → on crée une LM renouvellement
                pour l’année N
                - Pas de LM connue → on créée une LM inscription
            """
            self.ensure_one()
    
            lm_adhesion = self.lm_adhesion_id
    
            if not lm_adhesion:
                last_lm_ids = self.get_last_lm()
                year = fields.Date.today().year if not year else year
                if last_lm_ids:
                    lm_adhesion = last_lm_ids.filtered(lambda lm: lm.year == year)
    
                if not lm_adhesion:
                    if not last_lm_ids:
                        type_lm = "subscribe"
                    else:
                        type_lm = "renew"
                    ListeMinistere = self.env["scop.liste.ministere"]
                    lm_adhesion_id = ListeMinistere.sudo().create_folder(
                        self, year, type_lm
                    )
                    lm_adhesion = ListeMinistere.browse(lm_adhesion_id)
                    lm_adhesion.update_data_lm()
                    lm_adhesion.status = "2_publie"
                    self.lm_adhesion_id = lm_adhesion.id
            else:
                if not lm_adhesion.active:
                    lm_adhesion.write({"active": True})
    
            return lm_adhesion
    
        def get_last_lm(self):
            """
            Return last known lm for partner
            """
            self.ensure_one()
            lm_ids = self.env["scop.liste.ministere"].search(
                [("partner_id", "=", self.id), ("active", "in", [True, False])],
                order="year desc",
            )
            return lm_ids
    
        def get_liasse_adhesion(self, lm):
            """
            Return liasse linked to LM or create a new one
            :param lm:
            :return:
            """
            liasse_type_previ = "forecast"
            liasse_adhesion = lm.sudo().create_liasse_fiscale(liasse_type_previ)
            if not liasse_adhesion.L2052_FL:
                liasse_adhesion.update({"L2052_FL": self.ca_previsionnel})
            liasse_adhesion.is_qualified = True
            return liasse_adhesion
    
        def is_project_complete(self):
            """
            Check if project is complete : check fields LM-LF and docs
            :return: Logs of errors if needed
            """
            self.ensure_one()
            lm_adhesion = self.get_lm_adhesion()
    
            errors = str()
            errors_complete_fields = self.check_compulsory_fields(lm_adhesion)
            if errors_complete_fields:
                errors += errors_complete_fields
            errors_complete_docs = self.check_compulsory_docs()
            if errors_complete_docs:
                errors_str = str()
                for error in errors_complete_docs:
                    errors_str += "<li>" + error + "</li>"
                errors += (
                    "<hr/><strong>Documents manquants :</strong><ul>" + errors_str + "</ul>"
                )
            if errors:
                local_tz = timezone("Europe/Paris")
                utc_tz = timezone("UTC")
                self.list_logs = (
                    "<strong>"
                    + utc_tz.localize(fields.Datetime.now())
                    .astimezone(local_tz)
                    .strftime("%d/%m/%Y - %-H:%M")
                    + "</strong> - Impossible de soumettre le dossier à la CG Scop"
                    + errors
                )
                return False
            else:
                self.list_logs = False
                return True
    
        def check_compulsory_fields(self, lm):
            """
            Vérification des champs de la liste ministère et de la liasse fiscale
            :param lm:
            :return:
            """
            res = ""
            errors_lm = lm.check_compulsory_fields_lm()
            if errors_lm:
                res += (
                    "<hr/><strong>Dossier d'Adhésion : </strong><ul>" + errors_lm + "</ul>"
                )
            liasse_adhesion = self.get_liasse_adhesion(lm)
            errors_lf = liasse_adhesion.check_compulsory_fields_lf()
            if errors_lf:
                res += (
                    "<hr/><strong>Données financières :</strong><ul>" + errors_lf + "</ul>"
                )
            return res
    
        def check_compulsory_docs(self):
            """
            Vérification de la présence des docs obligatoires
            :return:
            """
            errors = list()
            if errors:
                return errors
            else:
                return False
    
        def create_num_adherent(self):
            """
            Generate new num adherent with sequence
            :return:
            """
            self.ensure_one()
            num = self.env["ir.sequence"].next_by_code("scop.membership.period")
            self.write({"member_number_int": num})
            return num
    
        def create_period_adhesion_cg(self, num_adherent):
            """
            Create new period adhesion for type CG
            :param num_adherent:
            :return:
            """
            self.ensure_one()
            type_id = self.env.ref("cgscop_partner.membership_type_1")
            self.create_period_adhesion(type_id, num_adherent)
            return True
    
        def create_period_adhesion_fede(self, num_adherent):
            """
            Create new period adhesion for type fédération if naf is linked to fede
            :param num_adherent:
            :return:
            """
            self.ensure_one()
    
            fede = self.naf_id.federation_id
            fede_com = self.env.ref("cgscop_partner.COM")
            fede_indus = self.env.ref("cgscop_partner.IND")
            fede_btp = self.env.ref("cgscop_partner.BTP")
    
            if fede == fede_com:
                type_id = self.env.ref("cgscop_partner.membership_type_2")
            elif fede == fede_indus:
                type_id = self.env.ref("cgscop_partner.membership_type_3")
            elif fede == fede_btp:
                type_id = self.env.ref("cgscop_partner.membership_type_4")
            else:
                type_id = None
            if type_id:
                self.create_period_adhesion(type_id, num_adherent)
                return True
            else:
                return False
    
        def create_period_adhesion(self, type_id, number):
            """
            Generic function to create period adhesion with type and number
            :param type_id:
            :param number:
            :return:
            """
            date = self.date_bureau_validation or fields.Date.today()
            if self.env["scop.membership.period"].search(
                [
                    ("partner_id", "=", self.id),
                    ("end", "=", False),
                    ("type_id", "=", type_id.id),
                ],
                limit=1,
            ):
                raise ValidationError(_("Une période d'adhésion existe déjà pour ce type"))
            else:
                self.env["scop.membership.period"].create(
                    {
                        "partner_id": self.id,
                        "type_id": type_id.id,
                        "start": date,
                        "start_stat": date,
                        "number": number,
                    }
                )
    
        def create_invoice_adhesion(self, lm):
            """
            Crée une facture d'adhésion avec l'article et le journal configurés
            ‐ Moins de 11 salariés (ou effectif inconnu) : 80€
            ‐ Entre 11 et 50 salariés : 160€
            ‐ Plus de 50 salariés : 235€
            :param lm:
            :return:
            """
            self.ensure_one()
            product_id = self.env.company.product_adhesion_id
            journal_id = self.env.company.journal_adhesion_id
            if not (product_id or journal_id):
                raise ValidationError(
                    _("Vous devez configurer un article et un journal d'adhésion !")
                )
            else:
                effectif = lm.eff_tt
                amount_adhesion = self.get_amount_adhesion(effectif)
    
                Invoice = self.env["account.move"]
    
                date_invoice = self.date_bureau_validation or fields.Date.today()
                adhesion_invoice = Invoice.create(
                    {
                        "partner_id": self.id,
                        "move_type": "out_invoice",
                        "journal_id": journal_id.id,
                        "state": "draft",
                        "invoice_date": date_invoice,
                        "invoice_line_ids": [
                            (
                                0,
                                None,
                                {
                                    "product_id": product_id.id,
                                    "account_id": product_id.property_account_income_id.id,
                                    "tax_ids": [(6, 0, product_id.taxes_id.ids)],
                                    "name": product_id.name,
                                    "price_unit": amount_adhesion,
                                    "price_subtotal": amount_adhesion,
                                },
                            ),
                        ],
                    }
                )
                adhesion_invoice.action_post()
    
                return adhesion_invoice
    
        def get_amount_adhesion(self, effectif):
            """
            Return amount adhésion thanks to effectif
            """
            self.ensure_one()
            if 11 <= effectif <= 50:
                amount_adhesion = 160
            elif effectif > 50:
                amount_adhesion = 235
            else:
                amount_adhesion = 80
            return amount_adhesion
    
        # ------------------------------------------------------
        # Override parent / Change of status
        # ------------------------------------------------------
        def scop_send_to_cg(self):
            """Hérite la fonction d'envoi de l'organisme à la CG
            pour validation afin de :
            - vérifier si le dossier d'adhésion est complet
            - positionner la date_transmission_cg avec la date du jour
            - affecter la coop à sa DIRECCTE
            - mettre à jour les lignes d'effectifs sur la fiche coop
            @return : True
            """
            if self.is_project_complete():
                super(ScopPartner, self).scop_send_to_cg()
                self.date_transmission_cg = fields.Date.today()
                self.lm_adhesion_id.maj_effectif_coop()
                self.lm_adhesion_id.status = "3_complet"
                message = "Le dossier d'adhésion a été transmis à la CG Scop"
            else:
                message = self.list_logs
            return {
                "type": "ir.actions.act_window.message",
                "title": _("Transmission du dossier d'Adhésion"),
                "is_html_message": True,
                "message": _(message),
            }
    
        def scop_abandonne(self):
            """
            Hérite la fonction d'abandon pour déterminer la date
    
            @return : True
            """
            super(ScopPartner, self).scop_abandonne()
            self.date_abort = fields.Date.today()
            return True
    
        def scop_suivi_non_adhesion(self):
            """
            Passe la coop en statut suivi sans devenir adhérente
            """
            wizard = self.env["scop.compulsory.fields.suivi.wizard"].create(
                {
                    "partner_id": self.id,
                }
            )
            return {
                "name": "Confirmation des champs obligatoires",
                "type": "ir.actions.act_window",
                "view_mode": "form",
                "res_model": "scop.compulsory.fields.suivi.wizard",
                "res_id": wizard.id,
                "target": "new",
            }
    
        def scop_valid_cg(self):
            """
            Inherit function to :
            - create period adhesion CG
            - create period adhesion Fédé if needed
            - create invoice adhesion
            - set liasse_fiscale_adhesion as qualified
            """
    
            if not self.lm_adhesion_id:
                raise ValidationError(
                    _("Cette coopérative n'a pas de dossier d'inscription")
                )
    
            res = super(ScopPartner, self).scop_valid_cg()
    
            # Create period adhésions with num adherent
            num_adherent = self.member_number_int or self.create_num_adherent()
            self.create_period_adhesion_cg(num_adherent)
            self.create_period_adhesion_fede(num_adherent)
            # TODO : check pour fede CAE si coop is CAE ?
    
            # Create invoice adhésion
            invoice = self.create_invoice_adhesion(self.lm_adhesion_id)
            self.invoice_adhesion_id = invoice
    
            # set liasse_fiscale_adhesion as qualified
            self.lm_adhesion_id.scop_liasse_fiscale_id.write({"is_qualified": True})
    
            return res
    
    
    class ResPartnerPrescriberCanal(models.Model):
        _name = "res.partner.prescriber.canal"
        _description = "Canal de Prescription"
    
        name = fields.Char("Canal de Prescription")