Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0] [MIG] survey_formio #117

Open
wants to merge 9 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions setup/survey_formio/odoo/addons/survey_formio
6 changes: 6 additions & 0 deletions setup/survey_formio/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
91 changes: 91 additions & 0 deletions survey_formio/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
==============
Survey Form.io
==============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:52a994bb6ab6a31abeab4ae06d4c01ac0d2d8f38f6464449317c84f32d8f9e64
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsurvey-lightgray.png?logo=github
:target: https://github.com/OCA/survey/tree/16.0/survey_formio
:alt: OCA/survey
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/survey-16-0/survey-16-0-survey_formio
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/survey&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds compatibility bewtween `form.io <https://formio.github.io/formio.js/app/builder>` and Survey. It adds a function on survey.survey that generates
a form.io compatible JSON that represents that survey. It also adds a function to generate a survey.user_input
from a JSON returned by form.io.
Use `survey.survey::generate_formio_json()` to get the json representing a survey that can be rendered using the form.io widget.
Use `survey.survey::user_input_from_formio()` to create a user_input with the answer from form.io.

It does not work with question of type 'matrix' because there's no corresponding compoment in form.io.

**Table of contents**

.. contents::
:local:

Known issues / Roadmap
======================

* Take validation fields into account when generating the JSON, only constr_mandatory is used at the moment.
* Implement translations <https://github.com/formio/formio.js/wiki/Translations>
* Use language settings for day and datetime parameters ?
* Implement function that warns user if his survey uses parameters not yet supported by this module
* Add validation for the JSON representing the answers

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/survey/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/survey/issues/new?body=module:%20survey_formio%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* ACSONE SA/NV

Contributors
~~~~~~~~~~~~

* Justine Doutreloux <[email protected]>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/survey <https://github.com/OCA/survey/tree/16.0/survey_formio>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions survey_formio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
15 changes: 15 additions & 0 deletions survey_formio/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2023 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Survey Form.io",
"summary": """
This module allows the generation of a form.io compatible JSON for a survey.""",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Odoo Community Association (OCA), ACSONE SA/NV",
"website": "https://github.com/OCA/survey",
"depends": ["survey"],
"data": [],
"demo": [],
}
27 changes: 27 additions & 0 deletions survey_formio/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * survey_formio
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-10-29 09:40+0000\n"
"Last-Translator: mymage <[email protected]>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"

#. module: survey_formio
#: model:ir.model,name:survey_formio.model_survey_survey
msgid "Survey"
msgstr "Sondaggio"

#. module: survey_formio
#: model:ir.model,name:survey_formio.model_survey_question
msgid "Survey Question"
msgstr "Domanda sondaggio"
24 changes: 24 additions & 0 deletions survey_formio/i18n/survey_formio.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * survey_formio
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: survey_formio
#: model:ir.model,name:survey_formio.model_survey_survey
msgid "Survey"
msgstr ""

#. module: survey_formio
#: model:ir.model,name:survey_formio.model_survey_question
msgid "Survey Question"
msgstr ""
2 changes: 2 additions & 0 deletions survey_formio/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import survey_question
from . import survey
154 changes: 154 additions & 0 deletions survey_formio/models/survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Copyright 2023 Acsone SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import json
from datetime import datetime

import pytz

from odoo import models


class SurveySurvey(models.Model):
_inherit = "survey.survey"

def _get_formio_display(self):
"""
Returns a string representing the form.io display
Correct values are form, wizard or pdf. At the moment only
form is supported.
In the future use questions_layout to determine display.
"""
self.ensure_one()
return "form"

def _get_survey_title(self):
"""
Returns a dict representing the title of the survey as a form.io
component.
"""
self.ensure_one()
return {
"label": "title",
"tag": "h1",
"content": self.title,
"key": "title",
"type": "htmlelement",
}

def _get_formio_components(self):
"""
Pages are not supported yet.
Returns a list of dict representing survey questions as form.io components
"""
self.ensure_one()
components = []
components.append(self._get_survey_title())
for question in self.question_ids:
component = question._get_formio_component()
if component:
components.append(component)
return components

def _from_formio_datetime_to_odoo(self, datetime_str):
"""
Form.io datetimes are given in the user's timezone and with an offset.
Odoo wants naïve datetimes.
Returns a naïve datetime as a string
Parameters:
datetime_str: string representing a datetime with an offset
"""
# In the json given by form.io, the offset is formatted as +hh:mm
# To be able to use strptime we need it to be formated as +hhmm
# We can't use the fromisoformat function because it's only available
# in Python v3.7+ and Odoo v13 is compatible with Python v3.6
index = datetime_str.rfind(":")
datetime_str = datetime_str[:index] + datetime_str[index + 1 :]
utc_datetime = datetime.strptime(
datetime_str, "%Y-%m-%dT%H:%M:%S%z"
).astimezone(pytz.UTC)
return utc_datetime.strftime("%Y-%m-%d %H:%M:%S")

def _from_formio_multiple_choice_to_odoo(self, multiple_choice_answers_dict):
"""
For a multiple choice question, the form.io answer has the
following format:
{"question_id": {
"answer_1_value": true/false
"answer_2_value": true/false
....
}}
Odoo expects the following format: [answer_id, answer_id, ...]
Form.io returns all the answers with true or false but odoo doesn't
distinguish them like that. If the answer isn't selected, it shouldn't appear
in the list containing the answers.
Returns a list with the correct format.
Parameters:
question_id: id of the survey.question
multiple_choice_answers_dict: dict given by form.io for a multiple choice question
"""
return [
key[1:] for (key, value) in multiple_choice_answers_dict.items() if value
]

def generate_formio_json(self):
"""
Returns a form.io conform json representation of a survey.
"""
self.ensure_one()
display = self._get_formio_display()
title = self.title
components = self._get_formio_components()
form_json = json.dumps(
{"display": display, "title": title, "components": components}
)
return form_json

def user_input_from_formio(self, formio_output, user_input_id=None):
"""
If no user_input_id is given, creates a user_input with the values in formio_output.
If there is a user_input_id, updates that user_input with the values in formio_output.
Parameters:
formio_output: json given by form.io as a dictionnary
user_input_id: survey.user_input id
"""
if not user_input_id:
user_input_id = self.env["survey.user_input"].create({"survey_id": self.id})
else:
user_input_id = self.env["survey.user_input"].browse(user_input_id)
form_io_answers = formio_output["data"]
for question in self.question_ids:
question_label = f"q{question.id}"
if form_io_answers.get(question_label):
if question.question_type == "datetime":
form_io_answers[
question_label
] = self._from_formio_datetime_to_odoo(
form_io_answers[question_label]
)
if question.question_type == "date":
# We only need the date part of the string, not the hours
form_io_answers[question_label] = form_io_answers[question_label][
:10
]
if question.question_type == "numerical_box":
# Odoo expects a string but form.io gives a number
# we have to cast it to avoid an error
form_io_answers[question_label] = str(
form_io_answers[question_label]
)
if question.question_type == "simple_choice":
# Odoo expects a string but form.io gives a number
# we have to cast it to avoid an error
form_io_answers[question_label] = form_io_answers[question_label][
1:
]
if question.question_type == "multiple_choice":
answers_dict = form_io_answers[question_label]
form_io_answers.pop(question_label)
form_io_answers[
question_label
] = self._from_formio_multiple_choice_to_odoo(answers_dict)
answer = form_io_answers.get(question_label)
user_input_id.save_lines(question, answer)
return user_input_id
Loading
Loading