@ -0,0 +1,48 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-OPL--1-red.svg |
||||
|
:target: https://www.odoo.com/documentation/16.0/legal/licenses.html#odoo-apps |
||||
|
:alt: License: OPL-1 |
||||
|
|
||||
|
Enhanced Survey Management |
||||
|
========================== |
||||
|
* Enhance your survey management with this module. |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
- www.odoo.com/documentation/16.0/setup/install.html |
||||
|
- Install our custom addon |
||||
|
|
||||
|
License |
||||
|
------- |
||||
|
Odoo Proprietary License v1.0 (OPL-1) |
||||
|
(https://www.odoo.com/documentation/16.0/legal/licenses.html#odoo-apps) |
||||
|
|
||||
|
Company |
||||
|
------- |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
* Developers: (V16) Mohammed Savad, Ahammed Harshad, Gee Paul Joby, Nihala Jebin, |
||||
|
(V17) Nihala KP |
||||
|
Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit https://www.cybrosys.com |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import controllers |
||||
|
from . import models |
@ -0,0 +1,68 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU LESSER |
||||
|
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
# (LGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
{ |
||||
|
'name': 'Enhanced Survey Management', |
||||
|
'version': '17.0.1.0.0', |
||||
|
'category': 'Extra Tools', |
||||
|
'summary': 'Enhance your survey management with new question kinds and more', |
||||
|
'description': """Upgrade your survey management capabilities with the ' |
||||
|
'addition of versatile question types. ' |
||||
|
'Capture specific timeframes by incorporating questions ' |
||||
|
'about the month, week, or range, ' |
||||
|
'enabling finer data analysis. ' |
||||
|
'Furthermore, enhance data collection by allowing ' |
||||
|
'respondents to upload files, ' |
||||
|
'fostering a more comprehensive understanding of their ' |
||||
|
'experiences.' |
||||
|
'Explore these new question types and optimize your survey ' |
||||
|
'strategy for enhanced insights.""", |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'website': "https://www.cybrosys.com", |
||||
|
'depends': ['base', 'survey', 'website'], |
||||
|
'data': [ |
||||
|
'data/enhanced_survey_management_data.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/survey_templates.xml', |
||||
|
'views/survey_question_views.xml', |
||||
|
'views/survey_input_print_templates.xml', |
||||
|
'views/survey_portal_templates.xml', |
||||
|
'views/survey_user_views.xml', |
||||
|
'views/survey_survey_views.xml' |
||||
|
], |
||||
|
'assets': { |
||||
|
'survey.survey_assets': [ |
||||
|
'https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css', |
||||
|
'https://cdn.jsdelivr.net/npm/flatpickr@4.6.3/dist/flatpickr.min.js', |
||||
|
'enhanced_survey_management/static/src/js/survey_form.js', |
||||
|
'enhanced_survey_management/static/src/js/survey_submit.js', |
||||
|
], |
||||
|
}, |
||||
|
'images': [ |
||||
|
'static/description/banner.jpg', |
||||
|
], |
||||
|
'license': 'LGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import enhanced_survey_management |
||||
|
from . import website_visibility |
||||
|
from . import xlsx_main |
@ -0,0 +1,121 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo.addons.portal.controllers.portal import CustomerPortal |
||||
|
from odoo import http |
||||
|
from odoo.http import request |
||||
|
|
||||
|
|
||||
|
class SurveyAnswerPortal(CustomerPortal): |
||||
|
""" Inherited CustomerPortal to add new portal view""" |
||||
|
|
||||
|
def _prepare_home_portal_values(self, counters): |
||||
|
""" Function : Prepare portal values for attended survey count |
||||
|
@return : Survey counts |
||||
|
""" |
||||
|
values = super(SurveyAnswerPortal, self)._prepare_home_portal_values( |
||||
|
counters) |
||||
|
if 'survey_count' in counters: |
||||
|
values['survey_count'] = request.env[ |
||||
|
'survey.survey'].sudo().search_count( |
||||
|
[('user_id', '=', request.uid), ('visibility', '=', True)]) |
||||
|
return values |
||||
|
|
||||
|
|
||||
|
class SurveyPortalView(http.Controller): |
||||
|
""" Survey portal controller """ |
||||
|
|
||||
|
@http.route('/my/survey/ans', type='http', auth="public", |
||||
|
website=True) |
||||
|
def portal_my_survey(self): |
||||
|
""" Controller to send survey data to portal """ |
||||
|
survey = request.env['survey.survey'].sudo().search( |
||||
|
[('user_id', '=', request.uid)]) |
||||
|
values = { |
||||
|
'survey_list': [{'id': rec.id, |
||||
|
'survey': rec.title, |
||||
|
'user_id': rec.user_id.name, |
||||
|
'email': rec.user_id.partner_id.email, |
||||
|
'status': rec.session_state |
||||
|
} for rec in survey if rec.visibility], |
||||
|
'page_name': 'survey' |
||||
|
} |
||||
|
return request.render( |
||||
|
"""enhanced_survey_management.portal_survey_result""", values) |
||||
|
|
||||
|
@http.route('/my/survey/<int:survey_id>', type="http", auth="public", |
||||
|
website=True) |
||||
|
def survey_view(self, survey_id): |
||||
|
""" Controller function to send specific survey data """ |
||||
|
question_list = [] |
||||
|
survey_questions_line = request.env[ |
||||
|
'survey.user_input.line'].sudo().search([ |
||||
|
('survey_id', '=', survey_id)]) |
||||
|
survey = request.env['survey.survey'].sudo().browse(survey_id) |
||||
|
for res in survey_questions_line: |
||||
|
question_list.append({ |
||||
|
'id': res.question_id.id, |
||||
|
'questions': res.question_id.title, |
||||
|
'section': res.create_date, |
||||
|
'question_type': res.question_id.question_type, |
||||
|
'score': res.answer_score, |
||||
|
'answer': res.display_name, |
||||
|
}) |
||||
|
values = { |
||||
|
'survey_questions': question_list, |
||||
|
'survey': survey.title, |
||||
|
'survey_date': survey.create_date, |
||||
|
'name': survey.user_id.partner_id.name, |
||||
|
'email': survey.user_id.partner_id.email, |
||||
|
'access_token': survey.access_token, |
||||
|
'page_name': 'survey', |
||||
|
'survey_boolean': True |
||||
|
} |
||||
|
return request.render( |
||||
|
"enhanced_survey_management.portal_survey_result_view", values) |
||||
|
|
||||
|
|
||||
|
class SurveyLoadContent(http.Controller): |
||||
|
"""Controller to load country and state to the survey""" |
||||
|
|
||||
|
@http.route('/survey/load_country', type="json", auth="public", |
||||
|
website=True, csrf=False) |
||||
|
def load_country(self): |
||||
|
"""Function to return country names for question type country""" |
||||
|
country_ids = request.env['res.country'].sudo().search([]) |
||||
|
return { |
||||
|
'id': country_ids.mapped('id'), |
||||
|
'name': country_ids.mapped('name'), |
||||
|
} |
||||
|
|
||||
|
@http.route('/survey/load_states', type="json", auth="public", |
||||
|
website=True, |
||||
|
csrf=False) |
||||
|
def load_states(self, **kwargs): |
||||
|
"""Function to return state names based on country""" |
||||
|
country_id = request.env['res.country'].sudo().search([ |
||||
|
('name', '=', kwargs['params']['country_id'])]) |
||||
|
state_ids = request.env['res.country.state'].sudo().search([ |
||||
|
('country_id', '=', country_id.id)]) |
||||
|
return { |
||||
|
'id': state_ids.mapped('id'), |
||||
|
'name': state_ids.mapped('name'), |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import http |
||||
|
from odoo.http import request |
||||
|
|
||||
|
|
||||
|
class WebsiteView(http.Controller): |
||||
|
"""Inherited http.Controller to add custom route""" |
||||
|
|
||||
|
@http.route('/public/survey', type='http', auth="public", |
||||
|
website=True) |
||||
|
def public_user_access(self): |
||||
|
""" Controller function to access survey from website """ |
||||
|
survey = request.env['survey.survey'].sudo().search( |
||||
|
[('access_mode', '=', 'website')]) |
||||
|
values = { |
||||
|
'survey_list': [{ |
||||
|
'title': rec.title, |
||||
|
'attempts': rec.attempts_limit, |
||||
|
'date': rec.create_date, |
||||
|
'access_token': rec.access_token |
||||
|
} for rec in survey], |
||||
|
} |
||||
|
return request.render("enhanced_survey_management.survey_visibility", |
||||
|
values) |
@ -0,0 +1,126 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
import io |
||||
|
import json |
||||
|
from datetime import datetime |
||||
|
|
||||
|
from odoo import http |
||||
|
from odoo.http import content_disposition, request |
||||
|
from odoo.tools.misc import xlsxwriter |
||||
|
|
||||
|
|
||||
|
class XlsxReportController(http.Controller): |
||||
|
"""Inherited http.Controller to add custom route""" |
||||
|
|
||||
|
@http.route('/xlsx_report/<model("survey.survey"):survey_id>', |
||||
|
type='http', auth='user', csrf=False) |
||||
|
def get_report_xlsx(self, survey_id=None, **args): |
||||
|
""" Function to create and print XLSX report""" |
||||
|
user_input_ids = request.env['survey.user_input'].search( |
||||
|
[("survey_id", '=', survey_id.id)]) |
||||
|
answers, title = [], '' |
||||
|
for rec in user_input_ids: |
||||
|
for res in rec: |
||||
|
answer='' |
||||
|
name = '' |
||||
|
for new in res.user_input_line_ids: |
||||
|
print(new.question_id) |
||||
|
if new.question_id.question_type in ['barcode', 'qr']: |
||||
|
continue |
||||
|
new_dt = str(rec.create_date).split('.') |
||||
|
if new.question_id.question_type == 'address': |
||||
|
data=json.loads(new.display_name) |
||||
|
for key in data: |
||||
|
if data[key]: |
||||
|
answer+=f'{data[key]},' |
||||
|
answers.append([rec.id, rec.nickname, new_dt[0], |
||||
|
new.question_id.title, answer]) |
||||
|
elif new.question_id.question_type == 'name': |
||||
|
data = json.loads(new.display_name) |
||||
|
for key in data: |
||||
|
if data[key]: |
||||
|
name += f'{data[key]} ' |
||||
|
answers.append([rec.id, rec.nickname, new_dt[0], |
||||
|
new.question_id.title, name]) |
||||
|
elif new.question_id.question_type == 'time': |
||||
|
# Convert time to 12-hour format |
||||
|
time_str = new.display_name |
||||
|
time_parts = time_str.split('.') |
||||
|
hours = int(time_parts[0]) |
||||
|
minutes = int(time_parts[1]) if len( |
||||
|
time_parts) > 1 else 0 |
||||
|
|
||||
|
# Handle 24-hour to 12-hour conversion |
||||
|
time_obj = datetime.strptime(f'{hours}:{minutes}', |
||||
|
'%H:%M') |
||||
|
time_12hr = time_obj.strftime('%I:%M %p') |
||||
|
answers.append([rec.id, rec.nickname, new_dt[0], |
||||
|
new.question_id.title, time_12hr]) |
||||
|
|
||||
|
|
||||
|
else: |
||||
|
answers.append([rec.id, rec.nickname, new_dt[0], |
||||
|
new.question_id.title, new.display_name]) |
||||
|
answers.reverse() |
||||
|
response = request.make_response( |
||||
|
None, |
||||
|
headers=[ |
||||
|
('Content-Type', 'application/vnd.ms-excel'), |
||||
|
('Content-Disposition', |
||||
|
content_disposition(survey_id.title + '.xlsx')) |
||||
|
] |
||||
|
) |
||||
|
output = io.BytesIO() |
||||
|
workbook = xlsxwriter.Workbook(output, {'in_memory': True}) |
||||
|
sheet = workbook.add_worksheet() |
||||
|
sheet.set_column(1, 0, 25) |
||||
|
sheet.set_column(2, 0, 25) |
||||
|
sheet.set_column(3, 3, 50) |
||||
|
cell_format = workbook.add_format( |
||||
|
{'font_size': '12px', 'align': 'center'}) |
||||
|
head = workbook.add_format( |
||||
|
{'align': 'center', 'bold': True, 'font_size': '20px'}) |
||||
|
sub_title = workbook.add_format( |
||||
|
{'align': 'right', 'bold': True, 'font_size': '12px'}) |
||||
|
sub_title_content = workbook.add_format( |
||||
|
{'align': 'left', 'bold': True, 'font_size': '12px'}) |
||||
|
txt = workbook.add_format({'font_size': '10px'}) |
||||
|
sheet.merge_range('A2:D3', 'SURVEY MANAGEMENT REPORT', head) |
||||
|
sheet.write('A4', 'Title :', sub_title) |
||||
|
sheet.merge_range('B4:C4', survey_id.title, sub_title_content) |
||||
|
sheet.merge_range('A6:A7', 'Partner', cell_format) |
||||
|
sheet.merge_range('B6:B7', 'Submission Date & Time', cell_format) |
||||
|
sheet.merge_range('C6:C7', 'Question', cell_format) |
||||
|
sheet.merge_range('D6:D7', 'Answer', cell_format) |
||||
|
row = 7 |
||||
|
column = 0 |
||||
|
for rec in answers: |
||||
|
sheet.write(row, column, rec[1], txt) |
||||
|
sheet.write(row, column + 1, rec[2], txt) |
||||
|
sheet.write(row, column + 2, rec[3], txt) |
||||
|
sheet.write(row, column + 3, rec[4], txt) |
||||
|
row = row + 1 |
||||
|
workbook.close() |
||||
|
output.seek(0) |
||||
|
response.stream.write(output.read()) |
||||
|
output.close() |
||||
|
return response |
@ -0,0 +1,10 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo noupdate="1"> |
||||
|
<!-- Survey Website menu data --> |
||||
|
<record id="menu_survey" model="website.menu"> |
||||
|
<field name="name">Survey</field> |
||||
|
<field name="url">/public/survey</field> |
||||
|
<field name="parent_id" ref="website.main_menu"/> |
||||
|
<field name="sequence" type="int">80</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,6 @@ |
|||||
|
## Module <enhanced_survey_management> |
||||
|
|
||||
|
#### 17.05.2024 |
||||
|
#### Version 17.0.1.0.0 |
||||
|
#### ADD |
||||
|
- Initial Commit for Enhanced Survey Management |
@ -0,0 +1,27 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from . import question_selection |
||||
|
from . import survey_question |
||||
|
from . import survey_question_answer |
||||
|
from . import survey_survey |
||||
|
from . import survey_user_input |
||||
|
from . import survey_user_input_line |
@ -0,0 +1,34 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class QuestionSelection(models.Model): |
||||
|
"""Model to store options for selection type question""" |
||||
|
_name = 'question.selection' |
||||
|
_description = 'Selection Question' |
||||
|
|
||||
|
name = fields.Char(string='Name', help="Selection value.") |
||||
|
question_id = fields.Many2one('survey.question', |
||||
|
string="Question", |
||||
|
help="Field to store " |
||||
|
"question id in selection type.") |
@ -0,0 +1,94 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import api, fields, models, _ |
||||
|
from odoo.exceptions import ValidationError |
||||
|
|
||||
|
|
||||
|
class SurveyQuestion(models.Model): |
||||
|
""" Inherited survey.question to add custom question type""" |
||||
|
_inherit = 'survey.question' |
||||
|
|
||||
|
selection_ids = fields.One2many('question.selection', |
||||
|
'question_id', |
||||
|
string='Select', |
||||
|
help="""Field used to create selection type |
||||
|
questions""") |
||||
|
question_type = fields.Selection(selection_add=[ |
||||
|
('time', 'Time'), |
||||
|
('month', 'Month'), |
||||
|
('name', 'Name'), |
||||
|
('address', 'Address'), |
||||
|
('email', 'Email'), |
||||
|
('password', 'Password'), |
||||
|
('qr', 'Qrcode'), |
||||
|
('url', 'URL'), |
||||
|
('week', 'Week'), |
||||
|
('color', 'Color'), |
||||
|
('range', 'Range'), |
||||
|
('many2one', 'Many2one'), |
||||
|
('file', 'Upload File'), |
||||
|
('many2many', 'Many2many'), |
||||
|
('selection', 'Selection'), |
||||
|
('barcode', 'Barcode') |
||||
|
], help="Survey supported question types") |
||||
|
matrix_subtype = fields.Selection( |
||||
|
selection_add=[('custom', 'Custom Matrix')], |
||||
|
help="""Matrix selection type question""") |
||||
|
model_id = fields.Many2one('ir.model', string='Model', |
||||
|
domain=[('transient', '=', False)], |
||||
|
help="Many2one type question") |
||||
|
range_min = fields.Integer(string='Min', |
||||
|
help='Minimum range,range type question') |
||||
|
range_max = fields.Integer(string='Max', |
||||
|
help='Maximum range,range type question') |
||||
|
qrcode = fields.Text(string='Qrcode', |
||||
|
help='Show qrcode in survey') |
||||
|
qrcode_png = fields.Binary(string='Qrcode PNG', help="Qrcode PNG") |
||||
|
barcode = fields.Char(string='Barcode', help="Barcode number") |
||||
|
barcode_png = fields.Binary(string='Barcode PNG', |
||||
|
help="Saves barcode png file") |
||||
|
|
||||
|
@api.onchange('barcode') |
||||
|
def _onchange_barcode(self): |
||||
|
"""Onchange function to restrict barcode less-than 12 character """ |
||||
|
if self.barcode: |
||||
|
if len(self.barcode) < 12: |
||||
|
raise ValidationError( |
||||
|
_("Make sure barcode is at least 12 letters")) |
||||
|
if len(self.barcode) > 12: |
||||
|
raise ValidationError( |
||||
|
_("There should not be more than 12 " |
||||
|
"characters in a barcode")) |
||||
|
if not self.barcode.isdigit(): |
||||
|
raise ValidationError(_("Only digits are allowed.")) |
||||
|
|
||||
|
def get_selection_values(self): |
||||
|
"""Function return options for selection type question""" |
||||
|
return self.selection_ids |
||||
|
|
||||
|
def prepare_model_id(self, model): |
||||
|
"""Function to return options for many2one question""" |
||||
|
if model: |
||||
|
model_data = self.env[model.model].sudo().search([]) |
||||
|
return [rec.read([model_data._rec_name])[0] for rec in model_data] |
||||
|
model_data = self.env[self.model_id.model].sudo().search([]) |
||||
|
return [rec.read([model_data._rec_name])[0] for rec in model_data] |
@ -0,0 +1,46 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class SurveyQuestionAnswer(models.Model): |
||||
|
"""Inherit question answer model to add new answer type and model field""" |
||||
|
_inherit = 'survey.question.answer' |
||||
|
|
||||
|
answer_type = fields.Selection([ |
||||
|
('text_box', 'Multiple Lines Text Box'), |
||||
|
('char_box', 'Single Line Text Box'), |
||||
|
('numerical_box', 'Numerical Value'), |
||||
|
('time', 'Time'), |
||||
|
('email', 'Email'), |
||||
|
('password', 'Password'), |
||||
|
('range', 'Range'), |
||||
|
('month', 'Month'), |
||||
|
('url', 'URL'), |
||||
|
('week', 'Week'), |
||||
|
('color', 'Color'), |
||||
|
('many2one', 'Many2one')], help="Answer type", |
||||
|
string='Answer Type', readonly=False, store=True) |
||||
|
model_id = fields.Many2one('ir.model', string='Model', |
||||
|
domain=[('transient', '=', False)], |
||||
|
help="Select model for getting it's" |
||||
|
" values in survey") |
@ -0,0 +1,39 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class Survey(models.Model): |
||||
|
"""Inherited model to change survey visibility""" |
||||
|
_inherit = 'survey.survey' |
||||
|
|
||||
|
access_mode = fields.Selection(selection_add=[ |
||||
|
('website', 'website')], ondelete={'website': 'cascade'}) |
||||
|
visibility = fields.Boolean(string='Portal Visibility', |
||||
|
help="""Portal visibility of this survey""") |
||||
|
|
||||
|
def action_answer_report_download(self): |
||||
|
"""Function to generate report values""" |
||||
|
return { |
||||
|
'type': 'ir.actions.act_url', |
||||
|
'url': f'/xlsx_report/{self.id}' |
||||
|
} |
@ -0,0 +1,136 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Mohammed Savad, Ahammed Harshad (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
import json |
||||
|
from odoo import models |
||||
|
|
||||
|
|
||||
|
class SurveyUserInput(models.Model): |
||||
|
"""Inherited user input to make acceptable for custom question""" |
||||
|
_inherit = "survey.user_input" |
||||
|
|
||||
|
def _save_lines(self, question, answer, comment=None, overwrite_existing=True): |
||||
|
"""Function to save custom answers""" |
||||
|
old_answers = self.env['survey.user_input.line'].search([ |
||||
|
('user_input_id', '=', self.id), |
||||
|
('question_id', '=', question.id), ]) |
||||
|
print('answer',answer) |
||||
|
if question.question_type in ['password', 'range', 'time', 'url', |
||||
|
'email', 'range', 'many2many', |
||||
|
'file', 'many2one', 'week', 'color', |
||||
|
'month', 'address', 'name', 'selection', |
||||
|
'file', 'qr', 'barcode', 'signature']: |
||||
|
res = self._save_user_answers(question, old_answers, answer) |
||||
|
elif question.matrix_subtype == 'custom': |
||||
|
res = self._save_user_answers(question, old_answers, answer) |
||||
|
else: |
||||
|
res = super()._save_lines(question, answer, comment) |
||||
|
return res |
||||
|
|
||||
|
def _save_user_answers(self, question, user_input_line, answer): |
||||
|
"""Function to save custom answers""" |
||||
|
vals = (self._get_user_answers( |
||||
|
question, answer, question.question_type)) |
||||
|
if user_input_line: |
||||
|
user_input_line.write(vals) |
||||
|
else: |
||||
|
user_input_line = self.env['survey.user_input.line'].create(vals) |
||||
|
return user_input_line |
||||
|
|
||||
|
def _get_user_answers(self, question, answer, answer_type): |
||||
|
"""Function to save custom answers""" |
||||
|
vals = {'user_input_id': self.id, 'question_id': question.id, |
||||
|
'skipped': False, 'answer_type': answer_type, |
||||
|
} |
||||
|
if not answer or (isinstance(answer, str) and not answer.strip()): |
||||
|
vals.update(answer_type=None, skipped=True) |
||||
|
return vals |
||||
|
if question.question_type == 'time': |
||||
|
vals['value_time'] = float(answer.replace(":", ".")) |
||||
|
elif question.question_type == 'url': |
||||
|
vals['value_url'] = answer |
||||
|
elif question.question_type == 'password': |
||||
|
vals['value_password'] = answer |
||||
|
elif question.question_type == 'email': |
||||
|
vals['value_email'] = answer |
||||
|
elif question.question_type == 'range': |
||||
|
vals['value_range'] = answer |
||||
|
elif question.question_type == 'many2one': |
||||
|
vals['value_many2one'] = answer[0] |
||||
|
vals['value_many2one_option'] = answer[1] |
||||
|
elif question.question_type == 'many2many': |
||||
|
vals['value_many2many'] = answer |
||||
|
elif question.question_type == 'week': |
||||
|
vals['value_week'] = answer |
||||
|
elif question.question_type == 'color': |
||||
|
vals['value_color'] = answer |
||||
|
elif question.question_type == 'month': |
||||
|
vals['value_month'] = answer |
||||
|
elif question.question_type == 'matrix' \ |
||||
|
and question.matrix_subtype == 'custom': |
||||
|
vals['value_matrix'] = json.dumps(answer) |
||||
|
elif question.question_type == 'address': |
||||
|
vals['value_address'] = json.dumps(answer) |
||||
|
elif question.question_type == 'qr': |
||||
|
vals['value_qr'] = json.dumps(answer) |
||||
|
elif question.question_type == 'barcode': |
||||
|
vals['value_barcode'] = json.dumps(answer) |
||||
|
elif question.question_type == 'name': |
||||
|
vals['value_name'] = json.dumps(answer) |
||||
|
elif question.question_type == 'selection': |
||||
|
vals['value_selection'] = answer |
||||
|
elif question.question_type == 'file': |
||||
|
attachment = self.env['ir.attachment'].create({ |
||||
|
'name': str(answer[1]), 'datas': answer[0], 'type': 'binary' |
||||
|
}) |
||||
|
vals['value_file'] = int(attachment.id if attachment else False) |
||||
|
vals['filename'] = attachment.name if attachment else False |
||||
|
return vals |
||||
|
|
||||
|
def _save_line_matrix(self, question, old_answers, answers, comment): |
||||
|
"""Function to save custom matrix""" |
||||
|
if question.matrix_subtype == 'custom': |
||||
|
self._save_line(question, answers) |
||||
|
else: |
||||
|
vals_list = [] |
||||
|
if not answers and question.matrix_row_ids: |
||||
|
# add a False answer to force saving a skipped line |
||||
|
# this will make this question correctly considered as |
||||
|
# skipped in statistics |
||||
|
answers = {question.matrix_row_ids[0].id: [False]} |
||||
|
if answers: |
||||
|
for row_key, row_answer in answers.items(): |
||||
|
for answer in row_answer: |
||||
|
vals = self._get_line_answer_values(question, answer, |
||||
|
'suggestion') |
||||
|
vals['matrix_row_id'] = int(row_key) |
||||
|
vals_list.append(vals.copy()) |
||||
|
if comment: |
||||
|
vals_list.append( |
||||
|
self._get_line_comment_values(question, comment)) |
||||
|
old_answers.sudo().unlink() |
||||
|
return self.env['survey.user_input.line'].create(vals_list) |
||||
|
|
||||
|
def _save_line_selection_answer(self, question, answer): |
||||
|
"""Function to save selection type answers""" |
||||
|
vals = self._get_line_answer_values(question, answer, |
||||
|
question.question_type) |
||||
|
return self.env['survey.user_input.line'].create(vals) |
@ -0,0 +1,189 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Nihala KP (odoo@cybrosys.com) |
||||
|
# |
||||
|
# This program is under the terms of the Odoo Proprietary License v1.0(OPL-1) |
||||
|
# It is forbidden to publish, distribute, sublicense, or sell copies of the |
||||
|
# Software or modified copies of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
|
# DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
############################################################################### |
||||
|
import json |
||||
|
import textwrap |
||||
|
from datetime import datetime |
||||
|
from odoo import api, fields, models, _ |
||||
|
|
||||
|
|
||||
|
class SurveyUserInputLine(models.Model): |
||||
|
"""Inherited user input line to add custom answer types """ |
||||
|
_inherit = 'survey.user_input.line' |
||||
|
|
||||
|
answer_type = fields.Selection( |
||||
|
selection_add=[('url', 'URL'), |
||||
|
('many2one', 'Many2one'), |
||||
|
('many2many', 'Many2many'), |
||||
|
('week', 'Week'), |
||||
|
('time', 'Time'), |
||||
|
('color', 'Color'), |
||||
|
('email', 'Email'), |
||||
|
('month', 'Month'), |
||||
|
('name', 'Name'), |
||||
|
('matrix', 'Matrix'), |
||||
|
('address', 'Address'), |
||||
|
('selection', 'Selection'), |
||||
|
('time', 'Time'), |
||||
|
('password', 'Password'), |
||||
|
('email', 'Email'), |
||||
|
('range', 'Range'), |
||||
|
('file', 'File'), |
||||
|
('qr', 'Qrcode'), |
||||
|
('barcode', 'Barcode')], help="Custom answer types") |
||||
|
value_url = fields.Char(string='User URL', |
||||
|
help='Answer question type : URL') |
||||
|
value_email = fields.Char(string='User Email', |
||||
|
help="Answer question type : Email") |
||||
|
value_week = fields.Char(string='User Week', |
||||
|
help="Answer question type : Week") |
||||
|
value_color = fields.Char(string='User Color', |
||||
|
help="Answer question type : Color") |
||||
|
value_many2one = fields.Char(string='Survey Many2one', |
||||
|
help="Answer question type : Many2one") |
||||
|
value_many2one_option = fields.Char(string='Many2one selected', |
||||
|
help="Answer question type : Selected") |
||||
|
value_many2many = fields.Char(string='Survey Many2many', |
||||
|
help="Answer question type : Many2many") |
||||
|
value_time = fields.Float(string='Time Value', |
||||
|
help="Answer question type : Time") |
||||
|
value_matrix = fields.Text(string='Custom Matrix Values', |
||||
|
help="Answer question type : Custom Matrix") |
||||
|
value_selection = fields.Char(string='User Selection', |
||||
|
help="Answer question type : Selection") |
||||
|
value_password = fields.Char(string='Password Value', |
||||
|
help="Answer question type : Password") |
||||
|
value_range = fields.Char(string='Range Value', |
||||
|
help="Answer question type:Range") |
||||
|
value_file = fields.Many2one('ir.attachment', |
||||
|
string='Survey file', |
||||
|
help="Answer question type : Attachment") |
||||
|
filename = fields.Char(string='File', help="Attachment file name") |
||||
|
file_data = fields.Binary(string='File Data', |
||||
|
help="Attachment file data", |
||||
|
related="value_file.datas") |
||||
|
value_month = fields.Char(string='Month Value', |
||||
|
help="Answer question type : Month") |
||||
|
value_address = fields.Text(string='Address Value', |
||||
|
help="Answer question type : Address") |
||||
|
value_name = fields.Text(string='Name Values', |
||||
|
help="Answer question type : Full name") |
||||
|
value_qr = fields.Char(string='Qr Values', |
||||
|
help="Answer question type : QRcode") |
||||
|
value_barcode = fields.Char(string='Barcode Values', |
||||
|
help="Answer question type : Barcode") |
||||
|
|
||||
|
def get_value_time(self): |
||||
|
"""Function to return answer for question type time """ |
||||
|
if self.value_time: |
||||
|
return datetime.strptime(str(self.value_time).replace('.', ':'), |
||||
|
"%H:%M").strftime("%H:%M") |
||||
|
return None |
||||
|
|
||||
|
def get_value_address(self, field): |
||||
|
"""Function to return answer for question type address""" |
||||
|
data = json.loads(self[0].value_address.replace("'", "\"")) |
||||
|
print("data",data) |
||||
|
if data: |
||||
|
question_id = self[0].question_id.id |
||||
|
return data.get(f'{question_id}-{field}', |
||||
|
'') |
||||
|
return '' |
||||
|
|
||||
|
def get_value_matrix(self, item): |
||||
|
"""Function to return answer for custom matrix""" |
||||
|
data = json.loads(self.value_matrix) |
||||
|
if data: |
||||
|
question_id = self.question_id.id |
||||
|
return data[f'{item}-{question_id}'] |
||||
|
return None |
||||
|
|
||||
|
def get_value_name(self, field): |
||||
|
"""Function to return answer for Full name""" |
||||
|
data = json.loads(self.value_name) |
||||
|
if data: |
||||
|
question_id = self.question_id.id |
||||
|
return data[f'{question_id}-{field}'] |
||||
|
return '' |
||||
|
|
||||
|
@api.depends('answer_type') |
||||
|
def _compute_display_name(self): |
||||
|
"""Override compute function to add custom answer display""" |
||||
|
for line in self: |
||||
|
if line.answer_type == 'char_box': |
||||
|
line.display_name = line.value_char_box |
||||
|
elif line.answer_type == 'text_box' and line.value_text_box: |
||||
|
line.display_name = textwrap.shorten(line.value_text_box, |
||||
|
width=50, |
||||
|
placeholder=" [...]") |
||||
|
elif line.answer_type == 'numerical_box': |
||||
|
line.display_name = line.value_numerical_box |
||||
|
elif line.answer_type == 'date': |
||||
|
line.display_name = fields.Date.to_string(line.value_date) |
||||
|
elif line.answer_type == 'datetime': |
||||
|
line.display_name = fields.Datetime.to_string(line.value_datetime) |
||||
|
elif line.answer_type == 'time': |
||||
|
line.display_name = line.value_time |
||||
|
elif line.answer_type == 'month': |
||||
|
line.display_name = line.value_month |
||||
|
elif line.answer_type == 'address': |
||||
|
line.display_name = line.value_address |
||||
|
elif line.answer_type == 'name': |
||||
|
line.display_name = line.value_name |
||||
|
elif line.answer_type == 'url': |
||||
|
line.display_name = line.value_url |
||||
|
elif line.answer_type == 'many2one': |
||||
|
line.display_name = line.value_many2one_option |
||||
|
elif line.answer_type == 'many2many': |
||||
|
line.display_name = line.value_many2many |
||||
|
elif line.answer_type == 'week': |
||||
|
line.display_name = line.value_week |
||||
|
elif line.answer_type == 'time': |
||||
|
line.display_name = line.value_time |
||||
|
elif line.answer_type == 'email': |
||||
|
line.display_name = line.value_email |
||||
|
elif line.answer_type == 'range': |
||||
|
line.display_name = line.value_range |
||||
|
elif line.answer_type == 'matrix': |
||||
|
line.display_name = line.value_matrix |
||||
|
elif line.answer_type == 'password': |
||||
|
line.display_name = line.value_password |
||||
|
elif line.answer_type == 'signature': |
||||
|
line.display_name = line.value_signature |
||||
|
elif line.answer_type == 'color': |
||||
|
line.display_name = line.value_color |
||||
|
elif line.answer_type == 'selection': |
||||
|
line.display_name = line.value_selection |
||||
|
elif line.answer_type == 'barcode': |
||||
|
line.display_name = line.value_barcode |
||||
|
elif line.answer_type == 'qr': |
||||
|
line.display_name = line.value_qr |
||||
|
elif line.answer_type == 'file': |
||||
|
line.display_name = line.filename |
||||
|
elif line.answer_type == 'suggestion': |
||||
|
if line.matrix_row_id: |
||||
|
line.display_name = '%s: %s' % ( |
||||
|
line.suggested_answer_id.value, |
||||
|
line.matrix_row_id.value) |
||||
|
else: |
||||
|
line.display_name = line.suggested_answer_id.value |
||||
|
if not line.display_name: |
||||
|
line.display_name = _('Skipped') |
|
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 565 B |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 264 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 11 KiB |
@ -0,0 +1,62 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import publicWidget from "@web/legacy/js/public/public_widget"; |
||||
|
import { _t } from "@web/core/l10n/translation"; |
||||
|
import { cookie } from "@web/core/browser/cookie"; |
||||
|
import { utils as uiUtils } from "@web/core/ui/ui_service"; |
||||
|
|
||||
|
import SurveyPreloadImageMixin from "@survey/js/survey_preload_image_mixin"; |
||||
|
|
||||
|
publicWidget.registry.SurveyForm = publicWidget.Widget.extend(SurveyPreloadImageMixin, { |
||||
|
selector: '.o_survey_form', |
||||
|
events: { |
||||
|
'focus .o_select_Country': '_onSelectCountry', |
||||
|
'change .o_select_Country': '_onSelectState', |
||||
|
'change .o_select_many2many': '_onSelectMany2many', |
||||
|
}, |
||||
|
init(){ |
||||
|
this._super(...arguments); |
||||
|
this.rpc = this.bindService("rpc"); |
||||
|
}, |
||||
|
|
||||
|
_onSelectCountry: function(ev){ |
||||
|
/* |
||||
|
* method to load country |
||||
|
*/ |
||||
|
var self = this |
||||
|
this.rpc('/survey/load_country',{}) |
||||
|
.then(function (result){ |
||||
|
var count = 0; |
||||
|
self.$el.find(`#${ev.target.id}`).html('<option value="">Country</option>') |
||||
|
result['id'].forEach(element => { |
||||
|
self.$el.find(`#${ev.target.id}`).append( |
||||
|
`<option value='${result['name'][count]}'>${result['name'][count]}</option>` |
||||
|
) |
||||
|
count += 1 |
||||
|
}) |
||||
|
}); |
||||
|
}, |
||||
|
_onSelectState: function(ev){ |
||||
|
/* |
||||
|
* method to load states |
||||
|
*/ |
||||
|
var self = this |
||||
|
var country_id = ev.target.value |
||||
|
var question_id = ev.target.dataset.id |
||||
|
this.rpc('/survey/load_states',{ |
||||
|
params: { country_id }, |
||||
|
}).then(function (result){ |
||||
|
var count = 0; |
||||
|
self.$el.find(`#${question_id}-state`).html('<option value="">State</option>') |
||||
|
result['id'].forEach(element => { |
||||
|
self.$el.find(`#${question_id}-state`).append( |
||||
|
`<option value="${result['name'][count]}">${result['name'][count]}</option>` |
||||
|
) |
||||
|
count += 1 |
||||
|
}) |
||||
|
}); |
||||
|
}, |
||||
|
_onSelectMany2many: function(ev){ |
||||
|
this.$el.find('.o_select_many2many_text').val(this.$el.find('.o_select_many2many').val()) |
||||
|
} |
||||
|
}); |
||||
|
export default publicWidget.registry.SurveyForm; |
@ -0,0 +1,151 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import { |
||||
|
deserializeDate, |
||||
|
deserializeDateTime, |
||||
|
parseDateTime, |
||||
|
parseDate, |
||||
|
serializeDateTime, |
||||
|
serializeDate, |
||||
|
} from "@web/core/l10n/dates"; |
||||
|
import SurveyFormWidget from '@survey/js/survey_form'; |
||||
|
/* |
||||
|
* Including custom events to SurveyFormWidget |
||||
|
*/ |
||||
|
SurveyFormWidget.include({ |
||||
|
events:{ |
||||
|
'change .o_file': '_onChangeFile', |
||||
|
'change .o_survey_form_choice_item': '_onChangeChoiceItem', |
||||
|
'click .o_survey_matrix_btn': '_onMatrixBtnClick', |
||||
|
'click input[type="radio"]': '_onRadioChoiceClick', |
||||
|
'click button[type="submit"]': '_onSubmit', |
||||
|
'click .o_survey_choice_img img': '_onChoiceImgClick', |
||||
|
'focusin .form-control': '_updateEnterButtonText', |
||||
|
'focusout .form-control': '_updateEnterButtonText' |
||||
|
}, |
||||
|
_prepareSubmitValues: function (formData, params) { |
||||
|
var self = this; |
||||
|
formData.forEach(function (value, key) { |
||||
|
switch (key) { |
||||
|
case 'csrf_token': |
||||
|
case 'token': |
||||
|
case 'page_id': |
||||
|
case 'question_id': |
||||
|
params[key] = value; |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
// Get all question answers by question type
|
||||
|
var address = {} |
||||
|
var names = {} |
||||
|
var matrix = {} |
||||
|
var self = this; |
||||
|
this.$('[data-question-type]').each(function () { |
||||
|
switch ($(this).data('questionType')) { |
||||
|
case 'text_box': |
||||
|
case 'char_box': |
||||
|
case 'numerical_box': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'date': |
||||
|
case 'datetime': |
||||
|
const [parse, serialize] = |
||||
|
$(this).data("questionType") === "date" |
||||
|
? [parseDate, serializeDate] |
||||
|
: [parseDateTime, serializeDateTime]; |
||||
|
const date = parse(this.value); |
||||
|
params[this.name] = date ? serialize(date) : ""; |
||||
|
break; |
||||
|
case 'simple_choice_radio': |
||||
|
case 'multiple_choice': |
||||
|
params = self._prepareSubmitChoices(params, $(this), $(this).data('name')); |
||||
|
break; |
||||
|
case 'url': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'email': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'many2one': |
||||
|
params[this.name] = [this.value, $(this).find("option:selected").attr('data-value')]; |
||||
|
break; |
||||
|
case 'week': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'color': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'time': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'range': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'password': |
||||
|
params[this.name] = this.value; |
||||
|
break; |
||||
|
case 'month': |
||||
|
params[this.name] = this.value |
||||
|
break; |
||||
|
case 'address': |
||||
|
address[this.name] = this.value |
||||
|
if (this.name.endsWith('pin')){ |
||||
|
address[this.name.split("-")[0]+'-country'] = self.$el.find(`#${this.name.split("-")[0]+'-country'}`).val(), |
||||
|
address[this.name.split("-")[0]+'-state'] = self.$el.find(`#${this.name.split("-")[0]+'-state'}`).val() |
||||
|
params[this.name.split("-")[0]] = address |
||||
|
address = {} |
||||
|
break; |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case 'custom': |
||||
|
if (this.name == 'matrix-end'){ |
||||
|
params[this.id] = matrix} |
||||
|
if ($(this).attr('id') === 'select' && this.name){ |
||||
|
matrix[this.name] = $(this).find("option:selected").attr('data-value')} |
||||
|
if ($(this).attr('id') !== 'select' && this.name){ |
||||
|
matrix[this.name] = this.value |
||||
|
} |
||||
|
case 'matrix': |
||||
|
params = self._prepareSubmitAnswersMatrix(params, $(this)); |
||||
|
break; |
||||
|
case 'name': |
||||
|
names[this.name] = this.value |
||||
|
if (this.name.endsWith('last')){ |
||||
|
params[this.name.split("-")[0]] = names |
||||
|
break; |
||||
|
} |
||||
|
break; |
||||
|
case 'selection': |
||||
|
params[this.name] = this.value |
||||
|
break; |
||||
|
case 'file': |
||||
|
if ($(this)[0].files[0]){ |
||||
|
params[this.name] = [$(this).data('file-name'), $(this)[0].files[0]['name']] |
||||
|
break; |
||||
|
} |
||||
|
break; |
||||
|
case 'many2many': |
||||
|
params[this.name] = self.$el.find(`.${this.name}`).val() |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
_onChangeFile: function (ev) { |
||||
|
/* |
||||
|
* method to save attachments |
||||
|
*/ |
||||
|
const element = this.$(ev.target); |
||||
|
for (var i=0; i < element.length; i++){ |
||||
|
const elements = $(element[i]) |
||||
|
if (element[i].files[0] && elements.data('file') === parseInt(elements.attr('name'))) { |
||||
|
var file_name = element[i].files[0]['name'] |
||||
|
const reader = new FileReader(); |
||||
|
reader.onloadend = () => { |
||||
|
elements.attr('data-file-name', reader.result.split(',')[1]) |
||||
|
elements.attr('data-file', file_name) |
||||
|
}; |
||||
|
reader.readAsDataURL(element[i].files[0]); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
}) |
@ -0,0 +1,46 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Survey result view inherit to view input of custom question types --> |
||||
|
<template id="survey_page_print" name="Survey: print page(Inherit)" |
||||
|
inherit_id="survey.survey_page_print"> |
||||
|
<xpath expr="//div[@role='alert']" position="before"> |
||||
|
<t t-if="question.question_type in ['time','date', 'month', 'address', 'url', 'week', 'color', 'email', 'password', |
||||
|
'many2one', 'file','range','many2many', 'name', 'matrix', 'selection', 'qr', 'barcode']"> |
||||
|
<t t-if="question.question_type == 'time'" |
||||
|
t-call="enhanced_survey_management.question_time"/> |
||||
|
<t t-if="question.question_type == 'month'" |
||||
|
t-call="enhanced_survey_management.question_month"/> |
||||
|
<t t-if="question.question_type == 'url'" |
||||
|
t-call="enhanced_survey_management.question_url"/> |
||||
|
<t t-if="question.question_type == 'week'" |
||||
|
t-call="enhanced_survey_management.question_week"/> |
||||
|
<t t-if="question.question_type == 'color'" |
||||
|
t-call="enhanced_survey_management.question_color"/> |
||||
|
<t t-if="question.question_type == 'address'" |
||||
|
t-call="enhanced_survey_management.question_address"/> |
||||
|
<t t-if="question.question_type == 'email'" |
||||
|
t-call="enhanced_survey_management.question_email"/> |
||||
|
<t t-if="question.question_type == 'range'" |
||||
|
t-call="enhanced_survey_management.question_range"/> |
||||
|
<t t-if="question.question_type == 'selection'" |
||||
|
t-call="enhanced_survey_management.question_selection_choice"/> |
||||
|
<t t-if="question.question_type == 'password'" |
||||
|
t-call="enhanced_survey_management.question_password"/> |
||||
|
<t t-if="question.question_type == 'many2one'" |
||||
|
t-call="enhanced_survey_management.question_many2one"/> |
||||
|
<t t-if="question.question_type == 'name'" |
||||
|
t-call="enhanced_survey_management.question_name"/> |
||||
|
<t t-if="question.question_type == 'file'" |
||||
|
t-call="enhanced_survey_management.question_file"/> |
||||
|
<t t-if="question.question_type == 'matrix'" |
||||
|
t-call="enhanced_survey_management.question_matrix_custom"/> |
||||
|
<t t-if="question.question_type == 'many2many'" |
||||
|
t-call="enhanced_survey_management.question_many2many"/> |
||||
|
<t t-if="question.question_type == 'barcode'" |
||||
|
t-call="enhanced_survey_management.question_barcode"/> |
||||
|
<t t-if="question.question_type == 'qr'" |
||||
|
t-call="enhanced_survey_management.question_qr"/> |
||||
|
</t> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,132 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<!-- Survey portal Views --> |
||||
|
<template id="portal_my_home_survey" |
||||
|
name="survey" customize_show="True" |
||||
|
inherit_id="portal.portal_my_home" priority="20"> |
||||
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside"> |
||||
|
<t t-call="portal.portal_docs_entry"> |
||||
|
<t t-set="title">Survey</t> |
||||
|
<t t-set="url" t-value="'/my/survey/ans'"/> |
||||
|
<t t-set="placeholder_count" t-value="'survey_count'"/> |
||||
|
</t> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
<!-- Survey portal Breadcrumbs --> |
||||
|
<template id="portal_my_home_menu_survey" name="Portal layout : Survey menu" |
||||
|
inherit_id="portal.portal_breadcrumbs" |
||||
|
priority="20"> |
||||
|
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside"> |
||||
|
<li t-if="page_name == 'survey'"> |
||||
|
<a t-if="survey_boolean" t-attf-href="/my/survey/ans">/ |
||||
|
Surveys |
||||
|
</a> |
||||
|
<t t-else="">/ Surveys</t> |
||||
|
</li> |
||||
|
<li t-if="survey_boolean" class="breadcrumb-item active"> |
||||
|
/ |
||||
|
<t t-esc="survey"/> |
||||
|
</li> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
<!-- Survey portal Views: Surveys --> |
||||
|
<template id="portal_survey_result" name="Survey"> |
||||
|
<t t-call="portal.portal_layout"> |
||||
|
<t t-set="breadcrumbs_searchbar" t-value="True"/> |
||||
|
<t t-call="portal.portal_searchbar"> |
||||
|
<t t-set="title">Survey</t> |
||||
|
</t> |
||||
|
<table class="table rounded mb-0 bg-white o_portal_my_doc_table"> |
||||
|
<thead> |
||||
|
<tr class="active"> |
||||
|
<th class="text-right">Survey</th> |
||||
|
<th class="text-right">Partner</th> |
||||
|
<th class="text-right">Email</th> |
||||
|
<th class="text-right">Status</th> |
||||
|
<th class="text-right"/> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<t t-foreach="survey_list" t-as="survey"> |
||||
|
<tr> |
||||
|
<td class="text-right"> |
||||
|
<a t-attf-href="/my/survey/{{survey['id']}}"> |
||||
|
<span t-esc="survey['survey']"/> |
||||
|
</a> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="survey['user_id']"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="survey['email']"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="survey['status']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</table> |
||||
|
</t> |
||||
|
</template> |
||||
|
<!-- Survey portal views results --> |
||||
|
<template id="portal_survey_result_view" name="Survey Result"> |
||||
|
<t t-call="portal.portal_layout"> |
||||
|
<t t-set="breadcrumbs_searchbar" t-value="True"/> |
||||
|
<t t-call="portal.portal_searchbar"> |
||||
|
<t t-set="title">Survey Results</t> |
||||
|
</t> |
||||
|
<table class="table"> |
||||
|
<tr> |
||||
|
<td class="text-right"> |
||||
|
<strong>Survey:</strong> |
||||
|
<span t-esc="survey"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<strong>Created on:</strong> |
||||
|
<span t-esc="survey_date"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<strong>Partner:</strong> |
||||
|
<span t-esc="name"/> |
||||
|
</td> |
||||
|
<td> |
||||
|
<strong>Email:</strong> |
||||
|
<span t-esc="email"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<table class="table rounded mb-0 bg-white o_portal_my_doc_table"> |
||||
|
<thead> |
||||
|
<tr class="active"> |
||||
|
<th class="text-right">Questions</th> |
||||
|
<th class="text-right">Created Date</th> |
||||
|
<th class="text-right">Questions_type</th> |
||||
|
<th class="text-right">Answer</th> |
||||
|
<th class="text-right">Score</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<t t-foreach="survey_questions" t-as="qst"> |
||||
|
<tr> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="qst['questions']"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="qst['section']"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="qst['question_type']"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="qst['answer']" |
||||
|
style="white-space: normal !important;"/> |
||||
|
</td> |
||||
|
<td class="text-right"> |
||||
|
<span t-esc="qst['score']"/> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</table> |
||||
|
</t> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,199 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<odoo> |
||||
|
<record id="survey_question_form" model="ir.ui.view"> |
||||
|
<field name="name"> |
||||
|
survey.question.view.form.inherit.enhanced.survey.management |
||||
|
</field> |
||||
|
<field name="model">survey.question</field> |
||||
|
<field name="inherit_id" ref="survey.survey_question_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<!-- inherit question view to add custom preview of new question type. --> |
||||
|
<xpath expr="//div[hasclass('o_preview_questions')]" |
||||
|
position="inside"> |
||||
|
<!-- Time Zone --> |
||||
|
<div invisible="question_type != 'time' "> |
||||
|
<span>Work Start Time</span> |
||||
|
<br/> |
||||
|
<i class="fa fa-clock-o" role="img" |
||||
|
aria-label="Single Line" title="Single Line">  |
||||
|
  --:-- |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Email --> |
||||
|
<div invisible="question_type != 'email'"> |
||||
|
<span>Email</span> |
||||
|
<br/> |
||||
|
<i class="fa fa-envelope" role="img" |
||||
|
aria-label="Single Line" title="Single Line">  |
||||
|
  ____________ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Month Zone --> |
||||
|
<div invisible="question_type != 'month'"> |
||||
|
<span>Name one Month</span> |
||||
|
<br/> |
||||
|
<i class="fa fa-calendar" role="img" |
||||
|
aria-label="Single Line" title="Single Line">  |
||||
|
  ____________ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Password --> |
||||
|
<div invisible="question_type != 'password'"> |
||||
|
<span>Password</span> |
||||
|
<br/> |
||||
|
<i class="fa fa-lock" role="img" |
||||
|
aria-label="Single Line" title="Single Line">  |
||||
|
  ######### |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Range --> |
||||
|
<div invisible="question_type != 'range'"> |
||||
|
<span>Volume</span> |
||||
|
<br/> |
||||
|
<i>------</i> |
||||
|
<i class="fa fa-bullseye" role="img" |
||||
|
aria-label="Single Line" title="Single Line"> |
||||
|
</i> |
||||
|
<i>----</i> |
||||
|
</div> |
||||
|
<!-- Signature --> |
||||
|
<div invisible="question_type != 'signature'"> |
||||
|
<span>Signature</span> |
||||
|
<br/> |
||||
|
<i class="fa fa-edit" role="img" |
||||
|
aria-label="Single Line" title="Single Line">  |
||||
|
  _________ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Address Zone --> |
||||
|
<div invisible="question_type != 'address'"> |
||||
|
<span>Current Address</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Single Line" title="Single Line"> |
||||
|
    __________ |
||||
|
<br/>          __________ |
||||
|
<br/> |
||||
|
___ ___ ___<br/>______ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Name --> |
||||
|
<div invisible="question_type != 'name'"> |
||||
|
<span>Your Name</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Name" title="Single Line">  |
||||
|
  ___ ___ ___ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- URL --> |
||||
|
<div invisible="question_type != 'url'"> |
||||
|
<span>URL</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="URL" class="fa fa-link" |
||||
|
title="Single Line">    ________ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Week --> |
||||
|
<div invisible="question_type != 'week'"> |
||||
|
<span>Select a week</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Week" class="fa fa-calendar" |
||||
|
title="Week">   Week --, --- |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Color --> |
||||
|
<div invisible="question_type != 'color'"> |
||||
|
<span>Pick a color</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Color" class="fa fa-paint-brush" |
||||
|
title="Color">   ________ |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Qr Code --> |
||||
|
<div invisible="question_type != 'qr'"> |
||||
|
<span>Scan Qrcode</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Color" class="fa fa-qrcode" |
||||
|
title="Color">  |
||||
|
</i> |
||||
|
___________ |
||||
|
</div> |
||||
|
<!-- Qr Code --> |
||||
|
<div invisible="question_type != 'barcode'"> |
||||
|
<span>Scan Barcode</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Color" class="fa fa-barcode" |
||||
|
title="Color">  |
||||
|
</i> |
||||
|
___________ |
||||
|
</div> |
||||
|
<!-- Qr Code --> |
||||
|
<div invisible="question_type != 'file'"> |
||||
|
<span>Upload a file</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Color" class="fa fa-file" |
||||
|
title="Color">  |
||||
|
</i> |
||||
|
___________ |
||||
|
</div> |
||||
|
<!-- Qr Code --> |
||||
|
<div invisible="question_type != 'selection'"> |
||||
|
<span>Select from list</span> |
||||
|
<br/> |
||||
|
<i role="img" aria-label="Color" class="fa fa-angle-down" |
||||
|
title="Color">  |
||||
|
</i> |
||||
|
___________ |
||||
|
</div> |
||||
|
<!-- Many2one --> |
||||
|
<div invisible="question_type != 'many2one'"> |
||||
|
<span>Select a Product</span> |
||||
|
<br/> |
||||
|
___________ |
||||
|
<i role="img" aria-label="Color" class="fa fa-angle-down" |
||||
|
title="Color">  |
||||
|
</i> |
||||
|
</div> |
||||
|
<!-- Many2many --> |
||||
|
<div invisible="question_type != 'many2many'"> |
||||
|
<span>Select tags</span> |
||||
|
<br/> |
||||
|
_()_()_()_()_()_ |
||||
|
</div> |
||||
|
</xpath> |
||||
|
<!-- Adding necessary field related to custom question types --> |
||||
|
<xpath expr="//page[@name='answers']/group" position="inside"> |
||||
|
<group invisible="question_type not in ['many2one', 'many2many']"> |
||||
|
<field name="model_id" |
||||
|
required="question_type in ['many2one', 'many2many']"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="selection_ids" |
||||
|
invisible="question_type != 'selection'"> |
||||
|
<tree editable="bottom"> |
||||
|
<field name="name"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
<group invisible="question_type != 'range'"> |
||||
|
<field name="range_min"/> |
||||
|
<field name="range_max"/> |
||||
|
</group> |
||||
|
<group invisible="question_type != 'qr'"> |
||||
|
<field name="qrcode"/> |
||||
|
</group> |
||||
|
<group invisible="question_type != 'barcode'"> |
||||
|
<field name="barcode"/> |
||||
|
</group> |
||||
|
</xpath> |
||||
|
<!-- Adding matrix field related to matrix question types --> |
||||
|
<xpath expr="//field[@name='suggested_answer_ids']/tree/field[@name='value']" |
||||
|
position="after"> |
||||
|
<field name="answer_type" |
||||
|
column_invisible="parent.matrix_subtype != 'custom'"/> |
||||
|
<field name="model_id" |
||||
|
required="answer_type == 'many2one'" |
||||
|
column_invisible="parent.matrix_subtype != 'custom'"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |