You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

239 lines
11 KiB

# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Ajith V (odoo@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/>.
#
################################################################################
import io
import xlsxwriter
from odoo import api, fields, models, _
from odoo.tools import date_utils
from odoo.tools.safe_eval import json
from odoo.exceptions import ValidationError
class SurveyXlsReport(models.TransientModel):
"""This is the wizard model, We can filter the xls report using this
model"""
_name = 'survey.xlsx.report'
_description = 'Survey XLSX Report '
partner_id = fields.Many2one('res.partner', string="Partner",
help="Select for getting the report of the "
"user")
survey_ids = fields.Many2many('survey.survey', string="Survey Ids",
help="This field stores survey ids",
readonly=True)
@api.onchange('partner_id')
def _onchange_partner_id(self):
"""
Updates the domain of the 'partner_id' field based on the partners
who have completed the associated surveys.
This method iterates over the survey records linked to the current record
and searches for survey user inputs that are in a 'done' state. It collects
the partners associated with these completed surveys and sets the domain
for the 'partner_id' field accordingly.
If no partners have completed the surveys, a ValidationError is raised.
Raises:
ValidationError: If no partners have participated in the survey.
Returns:
dict: A dictionary containing the domain for the 'partner_id' field,
limited to the IDs of partners who have completed the surveys.
"""
partner_ids = []
for rec in self.survey_ids:
user_list = self.env['survey.user_input'].search(
[('survey_id', '=', rec._origin.id), ('state', '=', 'done')])
for dec in user_list.partner_id:
if dec.id not in partner_ids:
partner_ids.append(dec.id)
if not partner_ids:
raise ValidationError(_(
"There are no partners participating in this survey"))
return {'domain': {'partner_id': [('id', 'in', partner_ids)]}}
def action_print_survey_xlsx_report(self):
"""
Generates and returns an XLSX report containing survey responses.
This method is triggered by a button and compiles survey data into an
Excel file. It iterates through all linked surveys, filters completed
responses (in the 'done' state), and gathers relevant information such
as survey name, creation date, respondent's name, question title, and
corresponding answers.
The collected data is organized by survey name and structured into a
dictionary format, which is then passed to the report generation process.
If a specific partner is selected, the method filters the survey
responses to include only those from that partner.
Returns:
dict: An action that triggers the generation of an XLSX report with
the compiled survey data.
The returned action dictionary includes:
- 'type': Specifies the type of action (report generation).
- 'data': Contains model name, options (including the formatted survey data),
output format, and report name.
- 'report_type': Specifies the report type ('xlsx').
"""
data_dict = {}
for doc in self.survey_ids:
domain = [('survey_id', '=', doc.id), ('state', '=', 'done')]
if self.partner_id:
domain.append(('partner_id', '=', self.partner_id.id))
for record in self.env['survey.user_input'].search(domain):
for rec in self.env['survey.user_input.line'].search(
[('user_input_id', '=', record.id)]):
data = {
'survey_name': rec.survey_id.title,
'create_date': rec.create_date,
'user_name': rec.user_input_id.partner_id.name,
'question': rec.question_id.title,
'answer': rec.display_name,
}
# Check if the survey_name is already in the dictionary
survey_name = data['survey_name']
if survey_name not in data_dict:
data_dict[
survey_name] = []
data_dict[survey_name].append(data)
grouped_data_list = [
{'survey_name': survey_name, 'partner_id': self.partner_id.name,
'data': survey_data} for survey_name, survey_data in
data_dict.items()]
dict_data = {
'record': grouped_data_list
}
return {
'type': 'ir.actions.report',
'data': {
'model': 'survey.xlsx.report',
'options': json.dumps(dict_data,
default=date_utils.json_default),
'output_format': 'xlsx',
'report_name': 'Survey Question Answer Report',
},
'report_type': 'xlsx',
}
def get_xlsx_report(self, dict_data, response):
"""
Generates an XLSX report from the provided data and writes it to the response.
This method is responsible for creating an Excel report using the `xlsxwriter`
library. It processes the survey data contained in `dict_data` and formats it
into a structured XLSX report. The report includes details such as survey name,
respondent name, response date, questions, and answers.
Parameters:
dict_data (dict): A dictionary containing the survey data to be included
in the report. The dictionary should have a key 'record'
which holds a list of survey response data.
response (werkzeug.wrappers.Response): The HTTP response object where the
generated XLSX file will be written.
The report's layout adjusts based on whether a specific partner is associated
with the survey responses. If a partner is selected, the report will include
the partner's name; otherwise, it will show general response data.
The method does the following:
- Creates an in-memory XLSX file.
- Adds survey data to the worksheet.
- Applies formatting to the headers and cells.
- Writes the final XLSX file to the response stream.
Returns:
None: The function directly writes the XLSX report to the response object.
"""
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
sheet = workbook.add_worksheet()
format21 = workbook.add_format({'font_size': 10, 'bold': True})
font_size_8 = workbook.add_format({'font_size': 8})
head = workbook.add_format(
{'align': 'center', 'bold': True, 'font_size': '20px'})
heading_row_height = 30
if dict_data.get('record'):
if dict_data['record']:
row = 0
for records in dict_data.get('record'):
sheet.write(row, 0, records['survey_name'], head)
sheet.set_row(sheet.dim_rowmax, heading_row_height)
sheet.merge_range(sheet.dim_rowmax, 0, sheet.dim_rowmax, 4,
records['survey_name'],
head)
row += 1
if not records.get('partner_id'):
sheet.set_column('A:A', 5)
sheet.set_column('B:B', 15)
sheet.set_column('C:C', 15)
sheet.set_column('D:D', 76)
sheet.set_column('E:E', 56)
sheet.write(row, 0, 'Sl no', format21)
sheet.write(row, 1, 'Name', format21)
sheet.write(row, 2, 'Date', format21)
sheet.write(row, 3, 'Question', format21)
sheet.write(row, 4, 'Answer', format21)
row += 1
a = 1
for datas in records.get('data'):
sheet.write(row, 0, a, font_size_8)
a = a + 1
sheet.write(row, 1, datas.get('user_name'),
font_size_8)
sheet.write(row, 2, datas.get('create_date'),
font_size_8)
sheet.write(row, 3, datas.get('question'),
font_size_8)
sheet.write(row, 4, datas.get('answer'),
font_size_8)
row += 1
else:
sheet.set_column('A:A', 5)
sheet.set_column('B:B', 15)
sheet.set_column('C:C', 76)
sheet.set_column('D:D', 56)
sheet.write(row, 0, 'Sl no', format21)
sheet.write(row, 1, 'Date', format21)
sheet.write(row, 2, 'Question', format21)
sheet.write(row, 3, 'Answer', format21)
row += 1
a = 1
for datas in records.get('data'):
sheet.write(row, 0, a, font_size_8)
a = a + 1
sheet.write(row, 1, datas.get('create_date'),
font_size_8)
sheet.write(row, 2, datas.get('question'),
font_size_8)
sheet.write(row, 3, datas.get('answer'),
font_size_8)
row += 1
workbook.close()
output.seek(0)
response.stream.write(output.read())
output.close()