[ADD] survey_xlsx_expand_multiple_choice, survey_xlsx_extra_fields

survey_xlsx_expand_multiple_choice: expand multiple_choice questions into
one Oui/Non column per option, and matrix questions into one column per
row (value = selected option). Relies on the extension hooks added to
survey_xlsx.

survey_xlsx_extra_fields: bridge (auto_install) with survey_extra_fields
that excludes 'file' question types from the XLSX export.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 12:24:51 +02:00
parent d0afa2310d
commit e10ec8d752
12 changed files with 335 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
# Copyright 2025 Elabore
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_report

View File

@@ -0,0 +1,148 @@
# Copyright 2025 Elabore
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import io
import openpyxl
from odoo.addons.survey.tests import common
class TestExpandMultipleChoice(common.TestSurveyCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.mc_question = cls._add_question(
cls,
page=cls.page_0,
name="Favorite colors",
qtype="multiple_choice",
labels=[
{"value": "Red"},
{"value": "Green"},
{"value": "Blue"},
],
survey_id=cls.survey.id,
sequence=10,
)
cls.answer_red = cls.mc_question.suggested_answer_ids[0]
cls.answer_green = cls.mc_question.suggested_answer_ids[1]
cls.answer_blue = cls.mc_question.suggested_answer_ids[2]
# Input 1: selects Red and Green
input1 = cls._add_answer(cls, cls.survey, cls.survey_manager.partner_id)
cls._add_answer_line(cls, cls.mc_question, input1, cls.answer_red.id)
cls._add_answer_line(cls, cls.mc_question, input1, cls.answer_green.id)
input1._mark_done()
# Input 2: selects Blue only
input2 = cls._add_answer(cls, cls.survey, False, email="test2@example.com")
cls._add_answer_line(cls, cls.mc_question, input2, cls.answer_blue.id)
input2._mark_done()
# Matrix question (one choice per row): satisfaction grid
cls.matrix_question = cls._add_question(
cls,
page=cls.page_0,
name="Satisfaction",
qtype="matrix",
matrix_subtype="simple",
labels=[
{"value": "Pas du tout satisfait"},
{"value": "Satisfait"},
],
labels_2=[
{"value": "Tableaux de bord"},
{"value": "Relation client"},
],
survey_id=cls.survey.id,
sequence=20,
)
cls.col_unhappy = cls.matrix_question.suggested_answer_ids[0]
cls.col_happy = cls.matrix_question.suggested_answer_ids[1]
cls.row_dashboard = cls.matrix_question.matrix_row_ids[0]
cls.row_client = cls.matrix_question.matrix_row_ids[1]
# input1 answers the matrix: dashboard -> unhappy, client -> happy
cls._add_answer_line(
cls,
cls.matrix_question,
input1,
cls.col_unhappy.id,
answer_value_row=cls.row_dashboard.id,
)
cls._add_answer_line(
cls,
cls.matrix_question,
input1,
cls.col_happy.id,
answer_value_row=cls.row_client.id,
)
def _get_sheet(self):
report = self.env.ref("survey_xlsx.report_survey_xlsx")
rep = self.env["ir.actions.report"]._render(report, self.survey.ids, {})
wb = openpyxl.load_workbook(io.BytesIO(rep[0]))
return wb.worksheets[0]
def _find_col(self, sheet, header):
for col in range(1, sheet.max_column + 1):
if sheet.cell(1, col).value == header:
return col
return None
def test_headers(self):
sheet = self._get_sheet()
self.assertIsNotNone(
self._find_col(sheet, "Favorite colors / Red")
)
self.assertIsNotNone(
self._find_col(sheet, "Favorite colors / Green")
)
self.assertIsNotNone(
self._find_col(sheet, "Favorite colors / Blue")
)
def test_values(self):
sheet = self._get_sheet()
col_red = self._find_col(sheet, "Favorite colors / Red")
col_green = self._find_col(sheet, "Favorite colors / Green")
col_blue = self._find_col(sheet, "Favorite colors / Blue")
# Collect rows by (red, green, blue) values
rows = set()
for row in range(2, sheet.max_row + 1):
rows.add((
sheet.cell(row, col_red).value,
sheet.cell(row, col_green).value,
sheet.cell(row, col_blue).value,
))
self.assertIn(("Oui", "Oui", "Non"), rows)
self.assertIn(("Non", "Non", "Oui"), rows)
def test_matrix_headers(self):
sheet = self._get_sheet()
self.assertIsNotNone(
self._find_col(sheet, "Satisfaction / Tableaux de bord")
)
self.assertIsNotNone(
self._find_col(sheet, "Satisfaction / Relation client")
)
# No per-column expansion for matrices
self.assertIsNone(
self._find_col(sheet, "Satisfaction / Pas du tout satisfait")
)
def test_matrix_values(self):
sheet = self._get_sheet()
col_dashboard = self._find_col(sheet, "Satisfaction / Tableaux de bord")
col_client = self._find_col(sheet, "Satisfaction / Relation client")
values = set()
for row in range(2, sheet.max_row + 1):
values.add((
sheet.cell(row, col_dashboard).value,
sheet.cell(row, col_client).value,
))
self.assertIn(("Pas du tout satisfait", "Satisfait"), values)