From eb6afdadab45ae7631ae37edc3262b9740c2f978 Mon Sep 17 00:00:00 2001 From: Risvana Cybro Date: Thu, 7 Aug 2025 15:30:20 +0530 Subject: [PATCH] Aug 07: [FIX] Bug Fixed 'survey_upload_file' --- survey_upload_file/doc/RELEASE_NOTES.md | 10 ++- .../models/survey_user_input.py | 85 +++++++++++++------ .../static/src/js/survey_form_attachment.js | 70 ++++++--------- survey_upload_file/views/survey_templates.xml | 2 +- 4 files changed, 91 insertions(+), 76 deletions(-) diff --git a/survey_upload_file/doc/RELEASE_NOTES.md b/survey_upload_file/doc/RELEASE_NOTES.md index b439e2328..2ff2f9a97 100644 --- a/survey_upload_file/doc/RELEASE_NOTES.md +++ b/survey_upload_file/doc/RELEASE_NOTES.md @@ -1,12 +1,14 @@ ## Module #### 07.06.2024 -#### Version 16.0.1.0.0 +#### Version 17.0.1.0.0 #### ADD - Initial Commit for File Upload In Survey -#### 23.12.2024 +#### 05.08.2025 #### Version 17.0.1.0.1 -#### Update -- Updated with the issue in index. +#### BUG_FIX + +- Fixed the bug when updating multiple files. + diff --git a/survey_upload_file/models/survey_user_input.py b/survey_upload_file/models/survey_user_input.py index 4b57c49bf..130274608 100644 --- a/survey_upload_file/models/survey_user_input.py +++ b/survey_upload_file/models/survey_user_input.py @@ -19,7 +19,8 @@ # If not, see . # ############################################################################## -from odoo import models +from odoo import models, _ +from odoo.exceptions import UserError class SurveyUserInput(models.Model): @@ -37,21 +38,9 @@ class SurveyUserInput(models.Model): """ _inherit = "survey.user_input" - def _save_lines(self, question, answer, comment=None, - overwrite_existing=False): - """Save the user's answer for the given question.""" - old_answers = self.env['survey.user_input.line'].search([ - ('user_input_id', '=', self.id), - ('question_id', '=', question.id), ]) - if question.question_type in 'upload_file': - res = self._save_line_simple_answer(question, old_answers, answer) - else: - res = super()._save_lines(question, answer, comment, - overwrite_existing) - return res - - def _save_line_simple_answer(self, question, old_answers, answer): + def _save_line_file_upload(self, question, old_answers, answer): """ Save the user's file upload answer for the given question.""" + print('old_answers', old_answers) vals = self._get_line_answer_file_upload_values(question, 'upload_file', answer) if old_answers: @@ -60,27 +49,71 @@ class SurveyUserInput(models.Model): else: return self.env['survey.user_input.line'].create(vals) + def _save_lines(self, question, answer, comment=None, + overwrite_existing=True): + """ Save answers to questions, depending on question type. + + :param bool overwrite_existing: if an answer already exists for question and user_input_id + it will be overwritten (or deleted for 'choice' questions) in order to maintain data consistency. + :raises UserError: if line exists and overwrite_existing is False + """ + old_answers = self.env['survey.user_input.line'].search([ + ('user_input_id', '=', self.id), + ('question_id', '=', question.id) + ]) + if old_answers and not overwrite_existing: + raise UserError(_("This answer cannot be overwritten.")) + + if question.question_type in ['char_box', 'text_box', 'numerical_box', + 'date', 'datetime']: + self._save_line_simple_answer(question, old_answers, answer) + if question.save_as_email and answer: + self.write({'email': answer}) + if question.save_as_nickname and answer: + self.write({'nickname': answer}) + + elif question.question_type in ['simple_choice', 'multiple_choice']: + self._save_line_choice(question, old_answers, answer, comment) + elif question.question_type == 'matrix': + self._save_line_matrix(question, old_answers, answer, comment) + elif question.question_type == 'upload_file': + self._save_line_file_upload(question, old_answers, answer) + else: + raise AttributeError( + question.question_type + ": This type of question has no saving function") + def _get_line_answer_file_upload_values(self, question, answer_type, answer): - """Get the values to use when creating or updating a user input line - for a file upload answer.""" + answer = answer[0] vals = { 'user_input_id': self.id, 'question_id': question.id, 'skipped': False, 'answer_type': answer_type, + 'display_name': 'Upload File', } + if answer_type == 'upload_file': - attachment_ids = [] - if len(answer) >= 2: - file_data = answer[0] - file_name = answer[1] - for file in range(len(answer[1])): + # Parse JSON if needed + + attachments = [] + for file_info in answer: + if not isinstance(file_info, dict): + raise UserError("Each uploaded file must be a dictionary.") + + file_data = file_info.get('data') + file_name = file_info.get('name') + + if file_data and file_name: attachment = self.env['ir.attachment'].create({ - 'name': file_name[file], + 'name': file_name, 'type': 'binary', - 'datas': file_data[file], + 'datas': file_data, }) - attachment_ids.append(attachment.id) - vals['value_file_data_ids'] = attachment_ids + attachments.append((4, attachment.id)) + else: + raise UserError("Missing file name or data.") + + vals['value_file_data_ids'] = attachments + return vals diff --git a/survey_upload_file/static/src/js/survey_form_attachment.js b/survey_upload_file/static/src/js/survey_form_attachment.js index cf6450d27..e617486fa 100644 --- a/survey_upload_file/static/src/js/survey_form_attachment.js +++ b/survey_upload_file/static/src/js/survey_form_attachment.js @@ -12,50 +12,30 @@ publicWidget.registry.SurveyFormUpload = publicWidget.Widget.extend(SurveyPreloa this._super(...arguments); this.rpc = this.bindService("rpc"); }, - /** On adding file function */ - _onFileChange: function(event) { - var self = this; - var files = event.target.files; - var fileNames = []; - var dataURLs = []; - for (let i = 0; i < files.length; i++) { - var reader = new FileReader(); - reader.readAsDataURL(files[i]); - reader.onload = function(e) { - var file = files[i]; - var filename = file.name; - var dataURL = e.target.result.split(',')[1]; /** split base64 data */ - fileNames.push(filename); - dataURLs.push(dataURL); - /** Set the data-oe-data and data-oe-file_name attributes of the input element self call el */ - var $input = self.$el.find('input.o_survey_upload_file'); - $input.attr('data-oe-data', JSON.stringify(dataURLs)); - $input.attr('data-oe-file_name', JSON.stringify(fileNames)); - // Create file list elements - var fileList = document.getElementById('fileList'); - fileList.innerHTML = ''; // clear previous contents of file list - var ul = document.createElement('ul'); - fileNames.forEach(function(fileName) { - var li = document.createElement('li'); - li.textContent = fileName; - ul.appendChild(li); - }); - // Create delete button - var deleteBtn = document.createElement('button'); - deleteBtn.textContent = 'Delete All'; - deleteBtn.addEventListener('click', function() { - // Clear file list - fileList.innerHTML = ''; - // Clear input field attributes - $input.attr('data-oe-data', ''); - $input.attr('data-oe-file_name', ''); - self.$el.find('input[type="file"]').val(''); - }); - // Append file list and delete button to file input container - fileList.appendChild(ul); - fileList.appendChild(deleteBtn); - } - } - }, + _onFileChange: function (ev) { + const inputEl = ev.currentTarget; + const files = ev.target.files; + if (!files || files.length === 0) return; + + const readFile = (file) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const base64 = reader.result.split(',')[1]; + resolve({ + data: base64, + name: file.name + }); + }; + reader.onerror = reject; + reader.readAsDataURL(file); + }); + }; + + Promise.all([...files].map(readFile)).then(results => { + inputEl.setAttribute('data-oe-data', JSON.stringify(results)); + }); + } + }); export default publicWidget.registry.SurveyFormUpload; diff --git a/survey_upload_file/views/survey_templates.xml b/survey_upload_file/views/survey_templates.xml index 8ffaaf51c..9e5571088 100644 --- a/survey_upload_file/views/survey_templates.xml +++ b/survey_upload_file/views/survey_templates.xml @@ -64,4 +64,4 @@ - + \ No newline at end of file