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
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							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()
 | |
| 
 |