From f39d8223c51902abb5aa2057e4d0c71bbb30a253 Mon Sep 17 00:00:00 2001 From: benjamin <benjamin@le-filament.com> Date: Thu, 6 Feb 2025 18:57:05 +0100 Subject: [PATCH] [UPD] add satisfaction survey configuration & update report xls & add checks for survey subscription --- __init__.py | 2 +- __manifest__.py | 2 + controllers/survey.py | 28 +++++++ data/message_type.xml | 8 ++ models/res_company.py | 7 ++ models/res_config_settings.py | 4 + models/survey_user_input.py | 4 + models/training.py | 11 ++- report/__init__.py | 1 + report/report_survey_xlsx.py | 14 ++++ security/survey_security.xml | 12 ++- templates/survey_message.xml | 23 ++++++ views/res_company.xml | 3 + views/res_config_settings.xml | 9 +++ views/survey_user_input.xml | 3 +- views/training.xml | 146 +++++++++++++++++++--------------- 16 files changed, 202 insertions(+), 75 deletions(-) create mode 100644 data/message_type.xml create mode 100644 report/__init__.py create mode 100644 report/report_survey_xlsx.py create mode 100644 templates/survey_message.xml diff --git a/__init__.py b/__init__.py index 72d3ea6..c0771f7 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -from . import controllers, models +from . import controllers, models, report diff --git a/__manifest__.py b/__manifest__.py index 1894c9c..27cd6d3 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -18,10 +18,12 @@ "data/mail_end_training.xml", "data/mail_subscription.xml", "data/mail_training_confirmation.xml", + "data/message_type.xml", # templates "templates/survey_closed.xml", "templates/survey_duplicated_answer.xml", "templates/survey_max_student.xml", + "templates/survey_message.xml", "templates/survey_template_management.xml", # views "views/res_company.xml", diff --git a/controllers/survey.py b/controllers/survey.py index 5214036..691ea2a 100644 --- a/controllers/survey.py +++ b/controllers/survey.py @@ -42,8 +42,36 @@ class TrainingSurvey(Survey): ) training_id = post.get("training_id") + if ( + survey_sudo.survey_type == "training" + and survey_sudo.training_survey_type == "subscribe" + and not training_id + ): + return request.env["ir.qweb"]._render( + "training_survey.survey_message", + { + "title": survey_sudo.title, + "message": "Inscription impossible, il semble que l'URL ne soit pas correcte.", + "main_object": survey_sudo, + }, + ) + if training_id: training = request.env["training.training"].sudo().browse(int(training_id)) + if not training.active or ( + training not in survey_sudo.training_ids + and training.program_id not in survey_sudo.program_ids + ): + return request.env["ir.qweb"]._render( + "training_survey.survey_message", + { + "title": survey_sudo.title, + "training": training, + "message": "La page que vous recherchez n'est pas ou plus accessible.", + "main_object": training, + }, + ) + if training.date_limit and date.today() > training.date_limit: return request.env["ir.qweb"]._render( "training_survey.survey_closed", diff --git a/data/message_type.xml b/data/message_type.xml new file mode 100644 index 0000000..e9f4878 --- /dev/null +++ b/data/message_type.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <record id="mt_new_student" model="mail.message.subtype"> + <field name="name">Nouveau stagiaire</field> + <field name="res_model">training.training</field> + <field name="default" eval="True" /> + </record> +</odoo> diff --git a/models/res_company.py b/models/res_company.py index ba05ca2..c4b4993 100644 --- a/models/res_company.py +++ b/models/res_company.py @@ -7,6 +7,13 @@ from odoo import fields, models class ResCompany(models.Model): _inherit = "res.company" + # Questionnaire + is_satisfaction_mandatory = fields.Boolean( + string="Questionnaire de satisfaction obligatoire", + default=True, + help="Cette option permet de configurer si une formation peut être diffusée sans " + "questionnaire de satisfaction", + ) # Emails subscribe_mail_template_id = fields.Many2one( comodel_name="mail.template", string="Modèle d'email de pré-inscrition" diff --git a/models/res_config_settings.py b/models/res_config_settings.py index 06dd8af..f8a22db 100644 --- a/models/res_config_settings.py +++ b/models/res_config_settings.py @@ -7,6 +7,10 @@ from odoo import fields, models class ResConfigSettings(models.TransientModel): _inherit = "res.config.settings" + # Questionnaire + is_satisfaction_mandatory = fields.Boolean( + related="company_id.is_satisfaction_mandatory", readonly=False + ) # Emails subscribe_mail_template_id = fields.Many2one( related="company_id.subscribe_mail_template_id", readonly=False diff --git a/models/survey_user_input.py b/models/survey_user_input.py index 674d9d5..14df35d 100644 --- a/models/survey_user_input.py +++ b/models/survey_user_input.py @@ -93,6 +93,10 @@ class SurveyUserInput(models.Model): # Pré-inscription du stagiaire student_id = self._create_student() if student_id: + self.training_id.message_post( + body=f"Nouvelle inscription : {student_id.display_name}", + subtype_xmlid="training_survey.mt_new_student", + ) template_id = student_id.training_id.company_id._get_subscription_email() if template_id: template_id.send_mail( diff --git a/models/training.py b/models/training.py index cc9c4e5..c10d259 100644 --- a/models/training.py +++ b/models/training.py @@ -157,7 +157,10 @@ class Training(models.Model): # Inherit parent # ------------------------------------------------------ def action_valid(self): - if not self.satisfaction_survey_id: + if ( + not self.satisfaction_survey_id + and self.env.company.is_satisfaction_mandatory + ): raise UserError(_("Le questionnaire de satisfaction doit être configuré.")) return super().action_valid() @@ -165,7 +168,11 @@ class Training(models.Model): # Business function # ------------------------------------------------------ def _get_survey_xlsx(self, survey_id): - return self.env.ref("survey_xlsx.report_survey_xlsx").report_action(survey_id) + return ( + self.env.ref("survey_xlsx.report_survey_xlsx") + .with_context(training_id=self.id) + .report_action(docids=survey_id, data={"training_id": self.id}) + ) def get_registration_survey_start_url(self): url = self.registration_survey_id.get_start_url() diff --git a/report/__init__.py b/report/__init__.py new file mode 100644 index 0000000..2a41f6f --- /dev/null +++ b/report/__init__.py @@ -0,0 +1 @@ +from . import report_survey_xlsx diff --git a/report/report_survey_xlsx.py b/report/report_survey_xlsx.py new file mode 100644 index 0000000..21acef0 --- /dev/null +++ b/report/report_survey_xlsx.py @@ -0,0 +1,14 @@ +# © 2024 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class ReportSurveyXlsx(models.AbstractModel): + _inherit = "report.survey.xlsx" + + def _get_input_domain(self, results): + domain = super()._get_input_domain(results) + if self.env.context.get("training_id"): + domain.append(("training_id", "=", self.env.context.get("training_id"))) + return domain diff --git a/security/survey_security.xml b/security/survey_security.xml index 641a52a..d7ba7c2 100644 --- a/security/survey_security.xml +++ b/security/survey_security.xml @@ -3,12 +3,10 @@ <record id="survey_server_rule" model="ir.rule"> <field name="name">survey multi-company</field> <field name="model_id" ref="survey.model_survey_survey" /> - <field name="perm_read" eval="True"/> - <field name="perm_write" eval="False"/> - <field name="perm_create" eval="False"/> - <field name="perm_unlink" eval="False"/> - <field - name="domain_force" - >[('company_id', 'in', company_ids + [False])]</field> + <field name="perm_read" eval="True" /> + <field name="perm_write" eval="False" /> + <field name="perm_create" eval="False" /> + <field name="perm_unlink" eval="False" /> + <field name="domain_force">[('company_id', 'in', company_ids + [False])]</field> </record> </odoo> diff --git a/templates/survey_message.xml b/templates/survey_message.xml new file mode 100644 index 0000000..c765ae1 --- /dev/null +++ b/templates/survey_message.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <template id="survey_message" name="Survey: Website message"> + <t t-call="web.frontend_layout"> + <t t-set="html_data" t-value="{'style': 'height: 100%;'}"/> + <t t-set="no_header" t-value="True"/> + <t t-set="no_footer" t-value="True"/> + + <div class="wrap d-flex align-items-center h-100"> + <div class="container"> + <div class="fs-3 fw-light"> + <span t-out="message" /> + </div> + <div class="mt-4" t-if="not hide_back_training_list"> + <a class="btn btn-primary" href="/formations/liste"> + Retour à la liste des formations + </a> + </div> + </div> + </div> + </t> + </template> +</odoo> diff --git a/views/res_company.xml b/views/res_company.xml index 7483679..286a72b 100644 --- a/views/res_company.xml +++ b/views/res_company.xml @@ -9,6 +9,9 @@ <field name="model">res.company</field> <field name="inherit_id" ref="training.res_company_training_form_view" /> <field name="arch" type="xml"> + <xpath expr="//field[@name='agreement_special_condition']" position="after"> + <field name="is_satisfaction_mandatory" widget="boolean_toggle" /> + </xpath> <xpath expr="//page[@name='training']/group" position="after"> <group string="Emails"> <group> diff --git a/views/res_config_settings.xml b/views/res_config_settings.xml index b854f6a..2f4e008 100644 --- a/views/res_config_settings.xml +++ b/views/res_config_settings.xml @@ -6,6 +6,15 @@ <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_internal_regulation']" position="after"> + <div class="row mt16" name="is_satisfaction_mandatory"> + <label + for="is_satisfaction_mandatory" + class="col-lg-6 o_light_label" + /> + <field name="is_satisfaction_mandatory" widget="boolean_toggle" /> + </div> + </xpath> <xpath expr="//div[@name='training_settings']" position="after"> <h2>Configuration des emails</h2> <div diff --git a/views/survey_user_input.xml b/views/survey_user_input.xml index 3140619..4c4421b 100644 --- a/views/survey_user_input.xml +++ b/views/survey_user_input.xml @@ -36,8 +36,7 @@ > <field name="training_id" - readonly="1" - attrs="{'invisible': [('training_id', '=', False)]}" + attrs="{'invisible': [('training_survey_type', '=', False)]}" /> <field name="training_survey_type" diff --git a/views/training.xml b/views/training.xml index bab001f..aa42995 100644 --- a/views/training.xml +++ b/views/training.xml @@ -40,76 +40,96 @@ <xpath expr="//notebook" position="inside"> <page string="Questionnaires" name="survey"> - <p class="o_horizontal_separator"> + <!-- Pré-inscription/Positionnement--> + <div class="o_horizontal_separator mb-3"> Pré-inscription/Positionnement - </p> - <p> - <field name="registration_survey_id" class="me-4" /> - <button - name="action_export_registration" - type="object" - icon="fa-file-o" - class="btn-outline-primary" - title="Exporter réponses positionnement" - attrs="{'invisible': [('registration_survey_id', '=', False)]}" - /> - </p> + </div> + <div class="row"> + <div class="col-8"> + <field name="registration_survey_id" /> + </div> + <div class="col-4 text-end"> + <button + name="action_export_registration" + type="object" + class="btn-outline-primary btn-sm" + title="Exporter les réponses" + attrs="{'invisible': [('registration_survey_id', '=', False)]}" + > + Exporter les réponses + </button> + </div> + </div> - <p class="o_horizontal_separator"> + <!-- AECI --> + <div class="o_horizontal_separator mt-5 mb-3"> AECI - </p> - <p> - <field name="aeci_survey_id" class="me-4" /> - <button - name="action_export_aeci" - type="object" - icon="fa-file-o" - class="btn-outline-primary" - title="Export réponses AECI" - attrs="{'invisible': [('aeci_survey_id', '=', False)]}" - /> - </p> + </div> + <div class="row"> + <div class="col-8"> + <field name="aeci_survey_id" /> + </div> + <div class="col-4 text-end"> + <button + name="action_export_aeci" + type="object" + class="btn-outline-primary btn-sm" + title="Exporter les réponses AECI" + attrs="{'invisible': [('aeci_survey_id', '=', False)]}" + > + Exporter les réponses + </button> + </div> + </div> - <p class="o_horizontal_separator"> + + <!-- AECT --> + <div class="o_horizontal_separator mt-5 mb-3"> AECT - </p> - <p> - <field name="aect_survey_id" class="me-4" /> - <button - name="action_export_aect" - type="object" - icon="fa-file-o" - class="btn-outline-primary" - title="Export réponses AECT" - attrs="{'invisible': [('aect_survey_id', '=', False)]}" - /> - </p> + </div> + <div class="row"> + <div class="col-8"> + <field name="aect_survey_id" /> + </div> + <div class="col-4 text-end"> + <button + name="action_export_aect" + type="object" + class="btn-outline-primary btn-sm" + title="Exporter les réponses AECT" + attrs="{'invisible': [('aect_survey_id', '=', False)]}" + > + Exporter les réponses + </button> + </div> + </div> - <p class="o_horizontal_separator"> + <!-- Satisfaction --> + <div class="o_horizontal_separator mt-5 mb-3"> Satisfaction - </p> - <p> - <field - name="satisfaction_survey_id" - class="me-4 col-12 col-md-6" - options="{'no_create': 1}" - /> - <button - name="action_create_satisfaction_survey" - type="object" - class="btn-outline-primary" - string="Créer un nouveau questionnaire de satisfaction" - attrs="{'invisible': [('satisfaction_survey_id', '!=', False)]}" - /> - <button - name="action_export_satisfaction" - type="object" - icon="fa-file-o" - class="btn-outline-primary" - title="Export réponses satisfaction" - attrs="{'invisible': [('satisfaction_survey_id', '=', False)]}" - /> - </p> + </div> + <div class="row"> + <div class="col-8"> + <field name="satisfaction_survey_id" /> + </div> + <div class="col-4 text-end"> + <button + name="action_create_satisfaction_survey" + type="object" + class="btn-outline-primary btn-sm" + string="Créer un nouveau questionnaire de satisfaction" + attrs="{'invisible': [('satisfaction_survey_id', '!=', False)]}" + /> + <button + name="action_export_satisfaction" + type="object" + class="btn-outline-primary btn-sm" + string="Export réponses satisfaction" + attrs="{'invisible': [('satisfaction_survey_id', '=', False)]}" + /> + </div> + </div> + </page> </xpath> </field> -- GitLab