From c7bd904ae233af1b372e7d39f68305b0058df14e Mon Sep 17 00:00:00 2001 From: benjamin <benjamin@le-filament.com> Date: Tue, 29 Oct 2024 17:16:35 +0100 Subject: [PATCH] [ADD] email by company and fix subscription error --- data/mail_aeci.xml | 4 +- data/mail_end_training.xml | 49 ++++++++------- data/mail_subscription.xml | 10 +-- data/mail_training_confirmation.xml | 50 +++++++++++++++ models/__init__.py | 2 + models/res_company.py | 53 ++++++++++++++++ models/res_config_settings.py | 22 +++++++ models/survey_question.py | 96 ++++++++++++++--------------- models/survey_user_input.py | 23 ++++--- models/training.py | 17 ++++- models/training_student.py | 38 ++++++++++-- views/res_company.xml | 34 ++++++++++ views/res_config_settings.xml | 66 ++++++++++++++++++++ 13 files changed, 363 insertions(+), 101 deletions(-) create mode 100644 data/mail_training_confirmation.xml create mode 100644 models/res_company.py create mode 100644 models/res_config_settings.py create mode 100644 views/res_company.xml create mode 100644 views/res_config_settings.xml diff --git a/data/mail_aeci.xml b/data/mail_aeci.xml index 075eb9f..9f9cfdb 100644 --- a/data/mail_aeci.xml +++ b/data/mail_aeci.xml @@ -37,9 +37,9 @@ >Questionnaire AECI</a> <br /><br /> Je vous remercie et vous souhaite bonne réception de ce courriel. - <br /><br /> - Bonne journée. <br /> + Bonne journée. + <br /><br /> <t t-if="object.training_id.company_id.training_user_contact.signature"> <t t-out="object.training_id.company_id.training_user_contact.signature or ''">--<br/>Mitchell Admin</t> </t> diff --git a/data/mail_end_training.xml b/data/mail_end_training.xml index 19223a8..696a4f2 100644 --- a/data/mail_end_training.xml +++ b/data/mail_end_training.xml @@ -27,29 +27,32 @@ <t t-out="slot.date_end" t-options="{'widget': 'datetime', 'format': 'HH:mm'}">12:00</t> </li> </ul> - </t> - <br /> - je vous adresse les liens vers deux formulaires en ligne que vous voudrez bien renseigner : - <ul> - <li> - <a t-att-href="env.context.get('aect_answer').get_start_url()">Autoévaluation des compétences terminales</a> - </li> - <li> - <a t-att-href="env.context.get('satisfaction_answer').get_start_url()">Evaluation de ta satisfaction</a> - </li> - </ul> - <br /><br /> - Je vous prie de bien vouloir trouver en pièce jointe ton <t t-out="object.get_certification_name()" /> - <br /><br /> - Je vous remercie et vous souhaite bonne réception de ce courriel. - <br /><br /> - Bonne journée. - <br /> - <t t-if="object.training_id.company_id.training_user_contact.signature"> - <t t-out="object.training_id.company_id.training_user_contact.signature or ''">--<br/>Mitchell Admin</t> - </t> - </p> - </div> + </t> + <br /> + je vous adresse + <span t-if="env.context.get('satisfaction_answer')">les liens vers deux formulaires </span> + <span t-else="">le lien vers le formulaire </span> + en ligne que vous voudrez bien renseigner : + <ul> + <li> + <a t-att-href="env.context.get('aect_answer').get_start_url()">Autoévaluation des compétences terminales</a> + </li> + <li t-if="env.context.get('satisfaction_answer')"> + <a t-att-href="env.context.get('satisfaction_answer').get_start_url()">Evaluation de ta satisfaction</a> + </li> + </ul> + <br /><br /> + Je vous prie de bien vouloir trouver en pièce jointe ton <t t-out="object.get_certification_name()" /> + <br /><br /> + Je vous remercie et vous souhaite bonne réception de ce courriel. + <br /> + Bonne journée. + <br /><br /> + <t t-if="object.training_id.company_id.training_user_contact.signature"> + <t t-out="object.training_id.company_id.training_user_contact.signature or ''">--<br/>Mitchell Admin</t> + </t> + </p> + </div> </field> <field name="report_template" ref="training.report_attestation_pdf" /> <field name="report_name">{{ object.get_certification_name() }} - {{ object.partner_id.name }}</field> diff --git a/data/mail_subscription.xml b/data/mail_subscription.xml index 51e2406..48afc7c 100644 --- a/data/mail_subscription.xml +++ b/data/mail_subscription.xml @@ -33,15 +33,15 @@ <br /><br /> Nous reviendrons vers vous très prochainement pour confirmer votre inscription. <br /><br /> - Je te remercie et te souhaite bonne réception de ce courriel. - <br /><br /> - Bonne journée. + Je vous remercie et vous souhaite bonne réception de ce courriel. <br /> + Bonne journée. + <br /><br /> <t t-if="object.training_id.company_id.training_user_contact.signature"> <t t-out="object.training_id.company_id.training_user_contact.signature or ''">--<br/>Mitchell Admin</t> </t> - </p> - </div> + </p> + </div> </field> <field name="lang">fr_FR</field> <field name="auto_delete" eval="False" /> diff --git a/data/mail_training_confirmation.xml b/data/mail_training_confirmation.xml new file mode 100644 index 0000000..164c7f2 --- /dev/null +++ b/data/mail_training_confirmation.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <record id="mail_template_training_confirmation" model="mail.template"> + <field name="name">Formation - Confirmation inscription</field> + <field name="model_id" ref="training.model_training_student" /> + <field name="subject">Formation {{ object.training_id.program_id.name }} - Confirmation de votre inscription</field> + <field name="email_from">{{ object.training_id.company_id.training_user_contact.login }} <{{ object.training_id.company_id.training_user_contact.name }}></field> + <field name="email_to">{{ (object.partner_id.email or object.email) }}</field> + <field name="description">Mail envoyé au stagiaire pour confirmer son inscription</field> + <field name="body_html" type="html"> + <div style="margin: 0px; padding: 0px; font-size: 13px;"> + <p style="margin: 0px; padding: 0px; font-size: 13px;"> + Bonjour, + <br /><br /> + Nous vous confirmons votre inscription à la formation <t t-out="object.training_id.program_id.name">Nom Formation</t> + qui se tiendra + <t t-if="len(object.training_id.slot_ids) == 1"> + le <t t-out="object.training_id.slot_ids[0].date_start" t-options="{'widget': 'date', 'format': 'dd/MM/YYYY'}">05/05/2024</t> de + <t t-out="object.training_id.slot_ids[0].date_start" t-options="{'widget': 'datetime', 'format': 'HH:mm'}">09:00</t> à + <t t-out="object.training_id.slot_ids[0].date_end" t-options="{'widget': 'datetime', 'format': 'HH:mm'}">12:00</t> + </t> + <t t-else=""> + aux dates suivantes : + <ul> + <li t-foreach="object.training_id.slot_ids" t-as="slot"> + <t t-out="slot.date_start" t-options="{'widget': 'date', 'format': 'dd/MM/YYYY'}">05/05/2024</t> de + <t t-out="slot.date_start" t-options="{'widget': 'datetime', 'format': 'HH:mm'}">09:00</t> à + <t t-out="slot.date_end" t-options="{'widget': 'datetime', 'format': 'HH:mm'}">12:00</t> + </li> + </ul> + </t> + <br /><br /> + <t t-if="object.training_id.company_id.training_internal_regulation"> + Vous trouverez en pièce joint le règlement intérieur de l'organisme de formation. + <br /><br /> + </t> + Je vous remercie et vous souhaite bonne réception de ce courriel. + <br /> + Bonne journée. + <br /><br /> + <t t-if="object.training_id.company_id.training_user_contact.signature"> + <t t-out="object.training_id.company_id.training_user_contact.signature or ''">--<br/>Mitchell Admin</t> + </t> + </p> + </div> + </field> + <field name="lang">fr_FR</field> + <field name="auto_delete" eval="False" /> + </record> +</odoo> diff --git a/models/__init__.py b/models/__init__.py index 09d1366..26f1a7e 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,3 +1,5 @@ +from . import res_company +from . import res_config_settings from . import survey from . import survey_question from . import survey_question_answer diff --git a/models/res_company.py b/models/res_company.py new file mode 100644 index 0000000..ba05ca2 --- /dev/null +++ b/models/res_company.py @@ -0,0 +1,53 @@ +# © 2024 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + # Emails + subscribe_mail_template_id = fields.Many2one( + comodel_name="mail.template", string="Modèle d'email de pré-inscrition" + ) + confirmation_mail_template_id = fields.Many2one( + comodel_name="mail.template", string="Modèle d'email de confirmation" + ) + aeci_mail_template_id = fields.Many2one( + comodel_name="mail.template", string="Modèle d'email AECI" + ) + end_mail_template_id = fields.Many2one( + comodel_name="mail.template", string="Modèle d'email de fin de formation" + ) + + # ------------------------------------------------------ + # Business methods + # ------------------------------------------------------ + def _get_subscription_email(self): + self.ensure_one() + if self.aeci_mail_template_id: + return self.aeci_mail_template_id + else: + return self.env.ref("training_survey.mail_template_training_subscription") + + def _get_confirmation_email(self): + self.ensure_one() + if self.aeci_mail_template_id: + return self.aeci_mail_template_id + else: + return self.env.ref("training_survey.mail_template_training_confirmation") + + def _get_aeci_email(self): + self.ensure_one() + if self.aeci_mail_template_id: + return self.aeci_mail_template_id + else: + return self.env.ref("training_survey.mail_template_training_aeci") + + def _get_end_training_email(self): + self.ensure_one() + if self.aeci_mail_template_id: + return self.aeci_mail_template_id + else: + return self.env.ref("training_survey.mail_template_training_end") diff --git a/models/res_config_settings.py b/models/res_config_settings.py new file mode 100644 index 0000000..06dd8af --- /dev/null +++ b/models/res_config_settings.py @@ -0,0 +1,22 @@ +# © 2024 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + # Emails + subscribe_mail_template_id = fields.Many2one( + related="company_id.subscribe_mail_template_id", readonly=False + ) + confirmation_mail_template_id = fields.Many2one( + related="company_id.confirmation_mail_template_id", readonly=False + ) + aeci_mail_template_id = fields.Many2one( + related="company_id.aeci_mail_template_id", readonly=False + ) + end_mail_template_id = fields.Many2one( + related="company_id.end_mail_template_id", readonly=False + ) diff --git a/models/survey_question.py b/models/survey_question.py index 24ad879..b63d172 100644 --- a/models/survey_question.py +++ b/models/survey_question.py @@ -1,7 +1,7 @@ # Copyright 2024 Le Filament (<https://le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import fields, models +from odoo import Command, fields, models class SurveyQuestion(models.Model): @@ -30,8 +30,8 @@ class SurveyQuestion(models.Model): ) if not partner_id: error_msg = ( - f"Votre email ne fait pas partie de la liste des emails autorisés pour " - f"répondre à ce questionnaire." + "Votre email ne fait pas partie de la liste des emails autorisés pour " + "répondre à ce questionnaire." ) return {self.id: error_msg} # Check authorized domains @@ -40,8 +40,8 @@ class SurveyQuestion(models.Model): answer_domain = answer[answer.index("@") + 1 :] if answer_domain not in domain_list: error_msg = ( - f"Votre email ne fait pas partie de la liste des domaines autorisés " - f"pour répondre à ce questionnaire." + "Votre email ne fait pas partie de la liste des domaines autorisés " + "pour répondre à ce questionnaire." ) return {self.id: error_msg} return super()._validate_char_box(answer) @@ -57,51 +57,47 @@ class SurveyQuestion(models.Model): # ------------------------------------------------------ # Business function # ------------------------------------------------------ - def _create_email_question(self, survey_id): - self.create( - { - "title": "Email", - "question_type": "char_box", - "sequence": 1, - "validation_email": True, - "save_as_email": True, - "constr_mandatory": True, - "survey_id": survey_id, - } - ) + def _get_email_question_values(self): + return { + "title": "Email", + "question_type": "char_box", + "sequence": 1, + "validation_email": True, + "save_as_email": True, + "constr_mandatory": True, + } - def _create_firstname_question(self, survey_id): - self.create( - { - "title": "Prénom", - "question_type": "char_box", - "sequence": 2, - "save_as_firstname": True, - "constr_mandatory": True, - "survey_id": survey_id, - } - ) + def _get_firstname_question_values(self): + return { + "title": "Prénom", + "question_type": "char_box", + "sequence": 2, + "save_as_firstname": True, + "constr_mandatory": True, + } - def _create_lastname_question(self, survey_id): - self.create( - { - "title": "Nom", - "question_type": "char_box", - "sequence": 3, - "save_as_nickname": True, - "constr_mandatory": True, - "survey_id": survey_id, - } - ) + def _get_lastname_question_values(self): + return { + "title": "Nom", + "question_type": "char_box", + "sequence": 3, + "save_as_nickname": True, + "constr_mandatory": True, + } - def _create_company_question(self, survey_id): - self.create( - { - "title": "Structure", - "question_type": "char_box", - "sequence": 4, - "save_as_company": True, - "constr_mandatory": True, - "survey_id": survey_id, - } - ) + def _get_company_question_values(self): + return { + "title": "Structure", + "question_type": "char_box", + "sequence": 4, + "save_as_company": True, + "constr_mandatory": True, + } + + def _get_subscribe_question_values(self): + return [ + Command.create(self._get_email_question_values()), + Command.create(self._get_lastname_question_values()), + Command.create(self._get_firstname_question_values()), + Command.create(self._get_company_question_values()), + ] diff --git a/models/survey_user_input.py b/models/survey_user_input.py index 4493c57..35c8fa5 100644 --- a/models/survey_user_input.py +++ b/models/survey_user_input.py @@ -82,6 +82,7 @@ class SurveyUserInput(models.Model): self.survey_id.survey_type == "training" and self.survey_id.training_survey_type == "subscribe" and self.training_id + and not self.student_id ): student_model = self.env["training.student"].sudo() student_id = student_model.create( @@ -94,19 +95,17 @@ class SurveyUserInput(models.Model): "email": self.email, } ) - # Création de la réponse au sondage et inscription - self.create( - { - "partner_id": self.partner_id.id, - "email": self.partner_id.email, - "nickname": self.nickname, - "firstname": self.firstname, - "company": self.company, - "survey_id": self.training_id.registration_survey_id.id, - "student_id": student_id.id, - "training_id": self.training_id.id, - } + # Mise à jour de la réponse au sondage et inscription + self.student_id = student_id + + template_id = ( + self.student_id.training_id.company_id._get_subscription_email() ) + if template_id: + template_id.send_mail( + self.student_id.id, + email_layout_xmlid="training.mail_training_layout", + ) # ------------------------------------------------------ # Compute diff --git a/models/training.py b/models/training.py index 95c3651..3a2539f 100644 --- a/models/training.py +++ b/models/training.py @@ -86,8 +86,19 @@ class Training(models.Model): def action_send_end_training_data(self): self.ensure_one() + if not self.company_id.training_number: + raise UserError( + _("Le numéro d'organisme de formation n'est pas configuré.") + ) + if not self.company_id.legal_person: + raise UserError(_("Le représentant légal n'est pas configuré.")) + if not self.company_id.training_user_contact: + raise UserError( + _("Le contact formation (contact email) n'est pas configuré.") + ) + self.action_done() - end_template_id = self.env.ref("training_survey.mail_template_training_end") + end_template_id = self.company_id._get_end_training_email() student_ids = self.student_ids.filtered( lambda s: s.state == "confirmed" and any( @@ -106,7 +117,7 @@ class Training(models.Model): email_layout_xmlid="training.mail_training_layout", ) self.message_post( - subject="Questionnaires AECT et Satisfaction envoyés", + subject=_("Questionnaires AECT et Satisfaction envoyés"), body=f"Participants : {', '.join(student_ids.mapped('partner_id.name'))}", ) @@ -131,7 +142,7 @@ class Training(models.Model): def action_valid(self): if not self.satisfaction_survey_id: raise UserError(_("Le questionnaire de satisfaction doit être configuré.")) - super().action_valid() + return super().action_valid() # ------------------------------------------------------ # Business function diff --git a/models/training_student.py b/models/training_student.py index b37a4dc..8ef8f73 100644 --- a/models/training_student.py +++ b/models/training_student.py @@ -79,10 +79,33 @@ class TrainingStudent(models.Model): if not self.training_id.company_id.training_user_contact: raise UserError( _( - "Le contact de référence de la structure de formation n'est pas configuré." + "Le contact de référence de la structure de formation " + "n'est pas configuré." ) ) - aeci_template_id = self.env.ref("training_survey.mail_template_training_aeci") + ctx = self.env.context.copy() + if ctx.get("default_state"): + ctx.pop("default_state") + aeci_template_id = self.training_id.company_id._get_aeci_email() + self.with_context(ctx)._create_and_send_survey( + self.training_id.program_id.aeci_survey_id, aeci_template_id + ) + + # ------------------------------------------------------ + # Inherit parent + # ------------------------------------------------------ + def action_confirmed(self): + res = super().action_confirmed() + if not self.training_id.company_id.training_user_contact: + raise UserError( + _( + "Le contact de référence de la structure de formation " + "n'est pas configuré." + ) + ) + + confirmation_template_id = self.training_id.company_id._get_confirmation_email() + training_internal_regulation = ( self.env["ir.attachment"] .sudo() @@ -99,13 +122,16 @@ class TrainingStudent(models.Model): regulation_copy = training_internal_regulation.copy( {"name": "Règlement intérieur"} ) - aeci_template_id.attachment_ids = [(4, regulation_copy.id)] - self._create_and_send_survey( - self.training_id.program_id.aeci_survey_id, aeci_template_id + confirmation_template_id.attachment_ids = [(4, regulation_copy.id)] + # Envoie l'email + confirmation_template_id.send_mail( + self.id, + email_layout_xmlid="training.mail_training_layout", ) # Supprime le règlement intérieur au template if training_internal_regulation: - aeci_template_id.attachment_ids = [(5, 0, 0)] + confirmation_template_id.attachment_ids = [(5, 0, 0)] + return res # ------------------------------------------------------ # Business methods diff --git a/views/res_company.xml b/views/res_company.xml new file mode 100644 index 0000000..7483679 --- /dev/null +++ b/views/res_company.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright 2024 Le Filament (<https://le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> +<odoo> + + <!-- Form View --> + <record id="res_company_training_survey_form_view" model="ir.ui.view"> + <field name="name">Company Training Survey Form View</field> + <field name="model">res.company</field> + <field name="inherit_id" ref="training.res_company_training_form_view" /> + <field name="arch" type="xml"> + <xpath expr="//page[@name='training']/group" position="after"> + <group string="Emails"> + <group> + <field + name="subscribe_mail_template_id" + options="{'no_create': 1}" + /> + <field + name="confirmation_mail_template_id" + options="{'no_create': 1}" + /> + <field + name="aeci_mail_template_id" + options="{'no_create': 1}" + /> + <field name="end_mail_template_id" options="{'no_create': 1}" /> + </group> + </group> + </xpath> + </field> + </record> + +</odoo> diff --git a/views/res_config_settings.xml b/views/res_config_settings.xml new file mode 100644 index 0000000..b854f6a --- /dev/null +++ b/views/res_config_settings.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <record id="res_config_settings_training_survey_view_form" model="ir.ui.view"> + <field name="name">res.config.settings.view.form.inherit.training.survey</field> + <field name="model">res.config.settings</field> + <field name="priority" eval="40" /> + <field name="inherit_id" ref="training.res_config_settings_view_form" /> + <field name="arch" type="xml"> + <xpath expr="//div[@name='training_settings']" position="after"> + <h2>Configuration des emails</h2> + <div + class="row mt16 o_settings_container" + name="training_mail_settings" + > + <div class="col-lg-6 o_setting_box"> + <div class="o_setting_left_pane" /> + <div class="o_setting_right_pane"> + <div class="content-group"> + <div class="row mt16"> + <label + for="subscribe_mail_template_id" + class="col-lg-6 o_light_label" + /> + <field + name="subscribe_mail_template_id" + options="{'no_create': 1}" + /> + </div> + <div class="row mt16"> + <label + for="confirmation_mail_template_id" + class="col-lg-6 o_light_label" + /> + <field + name="confirmation_mail_template_id" + options="{'no_create': 1}" + /> + </div> + <div class="row mt16"> + <label + for="aeci_mail_template_id" + class="col-lg-6 o_light_label" + /> + <field + name="aeci_mail_template_id" + options="{'no_create': 1}" + /> + </div> + <div class="row mt16"> + <label + for="end_mail_template_id" + class="col-lg-6 o_light_label" + /> + <field + name="end_mail_template_id" + options="{'no_create': 1}" + /> + </div> + </div> + </div> + </div> + </div> + </xpath> + </field> + </record> +</odoo> -- GitLab